Update README and add contrib dir
This commit is contained in:
28
contrib/ethernet/CMakeLists.txt
Normal file
28
contrib/ethernet/CMakeLists.txt
Normal file
@@ -0,0 +1,28 @@
|
||||
check_include_file_cxx(stdint.h HAVE_STDINT_H)
|
||||
if(HAVE_STDINT_H)
|
||||
add_definitions(-DHAVE_STDINT_H)
|
||||
endif()
|
||||
|
||||
set(examples_as_tests_sources)
|
||||
if(${ENABLE_EXAMPLES})
|
||||
set(examples_as_tests_sources
|
||||
#test/ethernet-examples-test-suite.cc
|
||||
)
|
||||
endif()
|
||||
|
||||
build_lib(
|
||||
LIBNAME ethernet
|
||||
SOURCE_FILES model/ethernet-channel.cc
|
||||
model/ethernet-header2.cc
|
||||
model/ethernet-net-device.cc
|
||||
model/switch-net-device.cc
|
||||
model/switch-channel.cc
|
||||
HEADER_FILES model/ethernet-channel.h
|
||||
model/ethernet-header2.h
|
||||
model/ethernet-net-device.h
|
||||
model/switch-net-device.h
|
||||
model/switch-channel.h
|
||||
LIBRARIES_TO_LINK ${libcore}
|
||||
TEST_SOURCES test/ethernet-test-suite.cc
|
||||
${examples_as_tests_sources}
|
||||
)
|
||||
22
contrib/ethernet/examples/CMakeLists.txt
Normal file
22
contrib/ethernet/examples/CMakeLists.txt
Normal file
@@ -0,0 +1,22 @@
|
||||
set(base_examples
|
||||
ethernet-point2point
|
||||
ethernet-point2point-withPropagationDelay
|
||||
ethernet-point2point-withSmallFifo
|
||||
ethernet-switched
|
||||
ethernet-switched-withLatencyCallback
|
||||
ethernet-switched-withPcap
|
||||
ethernet-switched-withRxTxCallback
|
||||
)
|
||||
foreach(
|
||||
example
|
||||
${base_examples}
|
||||
)
|
||||
build_lib_example(
|
||||
NAME ${example}
|
||||
SOURCE_FILES ${example}.cc
|
||||
LIBRARIES_TO_LINK ${libcore}
|
||||
${libnetwork}
|
||||
${libethernet}
|
||||
${libtraffic-generator}
|
||||
)
|
||||
endforeach()
|
||||
94
contrib/ethernet/examples/ethernet-point2point-10Gb.cc
Normal file
94
contrib/ethernet/examples/ethernet-point2point-10Gb.cc
Normal file
@@ -0,0 +1,94 @@
|
||||
#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/ethernet-net-device.h"
|
||||
#include "ns3/ethernet-channel.h"
|
||||
#include "ns3/ethernet-generator.h"
|
||||
#include "ns3/ethernet-header2.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example of the use of ethernet-net-device.cc ethernet-channel.cc on a network
|
||||
* composed of two end-stations connected by a 10Gb/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::FS) << " \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);
|
||||
|
||||
//Mandatory for multi-giga
|
||||
Time::SetResolution(Time::PS);
|
||||
|
||||
//Create two nodes
|
||||
Ptr<Node> n0 = CreateObject<Node>();
|
||||
Names::Add("ES1", n0);
|
||||
Ptr<Node> n1 = CreateObject<Node>();
|
||||
Names::Add("ES2", n1);
|
||||
|
||||
//Create and add a netDevice to each node
|
||||
Ptr<EthernetNetDevice> net0 = CreateObject<EthernetNetDevice>();
|
||||
net0->SetAttribute("DataRate", DataRateValue(DataRate("10Gb/s")));
|
||||
n0->AddDevice(net0);
|
||||
Names::Add("ES1#01", net0);
|
||||
Ptr<EthernetNetDevice> net1 = CreateObject<EthernetNetDevice>();
|
||||
net1->SetAttribute("DataRate", DataRateValue(DataRate("10Gb/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;
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
#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/ethernet-net-device.h"
|
||||
#include "ns3/ethernet-channel.h"
|
||||
#include "ns3/ethernet-generator.h"
|
||||
#include "ns3/ethernet-header2.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example of the use of ethernet-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<Node> n0 = CreateObject<Node>();
|
||||
Names::Add("ES1", n0);
|
||||
Ptr<Node> n1 = CreateObject<Node>();
|
||||
Names::Add("ES2", n1);
|
||||
|
||||
//Create and add a netDevice to each node
|
||||
Ptr<EthernetNetDevice> net0 = CreateObject<EthernetNetDevice>();
|
||||
net0->SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
|
||||
n0->AddDevice(net0);
|
||||
Names::Add("ES1#01", net0);
|
||||
Ptr<EthernetNetDevice> net1 = CreateObject<EthernetNetDevice>();
|
||||
net1->SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
|
||||
n1->AddDevice(net1);
|
||||
Names::Add("ES2#01", net1);
|
||||
|
||||
//Create a Ethernet Channel with a 10µs propagation delay (~2km) and attach
|
||||
//it two the two netDevices
|
||||
Ptr<EthernetChannel> channel = CreateObject<EthernetChannel>();
|
||||
channel->SetAttribute("Delay", TimeValue(MicroSeconds(10)));
|
||||
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;
|
||||
}
|
||||
108
contrib/ethernet/examples/ethernet-point2point-withSmallFifo.cc
Normal file
108
contrib/ethernet/examples/ethernet-point2point-withSmallFifo.cc
Normal file
@@ -0,0 +1,108 @@
|
||||
#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/ethernet-net-device.h"
|
||||
#include "ns3/ethernet-channel.h"
|
||||
#include "ns3/ethernet-generator.h"
|
||||
#include "ns3/ethernet-header2.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example of the use of ethernet-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 !");
|
||||
}
|
||||
|
||||
//A callback to log the pkt drop due to FIFO offerflow
|
||||
static void
|
||||
MacTxDropCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " drop due to FIFO overflow !");
|
||||
}
|
||||
|
||||
|
||||
|
||||
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<Node> n0 = CreateObject<Node>();
|
||||
Names::Add("ES1", n0);
|
||||
Ptr<Node> n1 = CreateObject<Node>();
|
||||
Names::Add("ES2", n1);
|
||||
|
||||
//Create and add a netDevice to each node
|
||||
Ptr<EthernetNetDevice> net0 = CreateObject<EthernetNetDevice>();
|
||||
net0->SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
|
||||
n0->AddDevice(net0);
|
||||
Names::Add("ES1#01", net0);
|
||||
Ptr<EthernetNetDevice> net1 = CreateObject<EthernetNetDevice>();
|
||||
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 for each netDevice.
|
||||
net0->SetAddress(Mac48Address::Allocate());
|
||||
net1->SetAddress(Mac48Address::Allocate());
|
||||
|
||||
//Allocate a FIFO for each netDevice.
|
||||
//5 packets size FIFO for net0
|
||||
Ptr<DropTailQueue<Packet>> q = CreateObject<DropTailQueue<Packet>>();
|
||||
q->SetAttribute("MaxSize", QueueSizeValue(QueueSize("5p")));
|
||||
net0->SetQueue(q);
|
||||
//Default size FIFO (i.e. 100 packets) for net1
|
||||
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
|
||||
//Application description
|
||||
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
|
||||
app0->Setup(net0);
|
||||
app0->SetAttribute("BurstSize", UintegerValue(10));
|
||||
app0->SetAttribute("PayloadSize", UintegerValue(1400));
|
||||
app0->SetAttribute("Period", TimeValue(Seconds(5)));
|
||||
|
||||
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));
|
||||
|
||||
//Callback to display the packet drop log
|
||||
context = Names::FindName(n0) + ":" + Names::FindName(net0);
|
||||
net0->TraceConnectWithoutContext("MacTxDrop", MakeBoundCallback(&MacTxDropCallback, context));
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(Seconds(10));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
91
contrib/ethernet/examples/ethernet-point2point.cc
Normal file
91
contrib/ethernet/examples/ethernet-point2point.cc
Normal file
@@ -0,0 +1,91 @@
|
||||
#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/ethernet-net-device.h"
|
||||
#include "ns3/ethernet-channel.h"
|
||||
#include "ns3/ethernet-generator.h"
|
||||
#include "ns3/ethernet-header2.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example of the use of ethernet-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<Node> n0 = CreateObject<Node>();
|
||||
Names::Add("ES1", n0);
|
||||
Ptr<Node> n1 = CreateObject<Node>();
|
||||
Names::Add("ES2", n1);
|
||||
|
||||
//Create and add a netDevice to each node
|
||||
Ptr<EthernetNetDevice> net0 = CreateObject<EthernetNetDevice>();
|
||||
net0->SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
|
||||
n0->AddDevice(net0);
|
||||
Names::Add("ES1#01", net0);
|
||||
Ptr<EthernetNetDevice> net1 = CreateObject<EthernetNetDevice>();
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
#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/trace-helper.h"
|
||||
#include <fstream>
|
||||
|
||||
#include "ns3/ethernet-net-device.h"
|
||||
#include "ns3/ethernet-channel.h"
|
||||
#include "ns3/ethernet-generator.h"
|
||||
#include "ns3/ethernet-header2.h"
|
||||
#include "ns3/switch-net-device.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example of the use of switch-net-device.cc switch-channel.cc
|
||||
* ethernet-net-device.cc ethernet-channel.cc on a network composed of three
|
||||
* end-stations connected with a 1Gb/s full duplex link
|
||||
* ES1 ==== SW ==== ES2
|
||||
* ==== ES3
|
||||
*/
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("Example");
|
||||
|
||||
|
||||
//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 write in a file the pkt latency hop by hop
|
||||
static void
|
||||
LatencyHopByHopCallback(Ptr<OutputStreamWrapper> stream, std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
Ptr<Packet> originalPacket = p->Copy();
|
||||
EthernetHeader2 ethHeader;
|
||||
originalPacket->RemoveHeader(ethHeader);
|
||||
|
||||
*stream->GetStream() << context << " : Packet #"<< p->GetUid() << " from "<< ethHeader.GetSrc() << "(VID:" << ethHeader.GetVid() << ") : ";
|
||||
TimestampTag tag;
|
||||
TypeId tid = tag.GetInstanceTypeId();
|
||||
ByteTagIterator i = p->GetByteTagIterator();
|
||||
while (i.HasNext())
|
||||
{
|
||||
ByteTagIterator::Item item = i.Next();
|
||||
if (tid == item.GetTypeId())
|
||||
{
|
||||
item.GetTag(tag);
|
||||
*stream->GetStream() << tag.GetTimestamp().GetNanoSeconds() << ",";
|
||||
}
|
||||
}
|
||||
*stream->GetStream() << "\n";
|
||||
}
|
||||
|
||||
|
||||
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 four nodes
|
||||
Ptr<Node> n0 = CreateObject<Node>();
|
||||
Names::Add("ES1", n0);
|
||||
Ptr<Node> n1 = CreateObject<Node>();
|
||||
Names::Add("ES2", n1);
|
||||
Ptr<Node> n2 = CreateObject<Node>();
|
||||
Names::Add("ES3", n2);
|
||||
Ptr<Node> n3 = CreateObject<Node>();
|
||||
Names::Add("SW", n3);
|
||||
|
||||
//Create and add a netDevice to each end station node
|
||||
Ptr<EthernetNetDevice> net0 = CreateObject<EthernetNetDevice>();
|
||||
n0->AddDevice(net0);
|
||||
Names::Add("ES1#01", net0);
|
||||
Ptr<EthernetNetDevice> net1 = CreateObject<EthernetNetDevice>();
|
||||
n1->AddDevice(net1);
|
||||
Names::Add("ES2#01", net1);
|
||||
Ptr<EthernetNetDevice> net2 = CreateObject<EthernetNetDevice>();
|
||||
n2->AddDevice(net2);
|
||||
Names::Add("ES3#01", net2);
|
||||
|
||||
//Create and add a netDevice to each switch port
|
||||
Ptr<EthernetNetDevice> swnet0 = CreateObject<EthernetNetDevice>();
|
||||
n3->AddDevice(swnet0);
|
||||
Names::Add("SW#01", swnet0);
|
||||
Ptr<EthernetNetDevice> swnet1 = CreateObject<EthernetNetDevice>();
|
||||
n3->AddDevice(swnet1);
|
||||
Names::Add("SW#02", swnet1);
|
||||
Ptr<EthernetNetDevice> swnet2 = CreateObject<EthernetNetDevice>();
|
||||
n3->AddDevice(swnet2);
|
||||
Names::Add("SW#03", swnet2);
|
||||
|
||||
//Create Ethernet Channels and connect switch to the end-stations
|
||||
Ptr<EthernetChannel> channel0 = CreateObject<EthernetChannel>();
|
||||
net0->Attach(channel0);
|
||||
swnet0->Attach(channel0);
|
||||
Ptr<EthernetChannel> channel1 = CreateObject<EthernetChannel>();
|
||||
net1->Attach(channel1);
|
||||
swnet1->Attach(channel1);
|
||||
Ptr<EthernetChannel> channel2 = CreateObject<EthernetChannel>();
|
||||
net2->Attach(channel2);
|
||||
swnet2->Attach(channel2);
|
||||
|
||||
//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(swnet0);
|
||||
sw->AddSwitchPort(swnet1);
|
||||
sw->AddSwitchPort(swnet2);
|
||||
|
||||
//Allocate a Mac address and create 2 FIFOs (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>>());
|
||||
sw->SetAddress(Mac48Address::Allocate());
|
||||
swnet0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
swnet1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
swnet2->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
swnet0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
swnet1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
swnet2->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
|
||||
//Add forwarding table
|
||||
sw->AddForwardingTableEntry(Mac48Address::ConvertFrom(net2->GetAddress()), 1, {swnet2});
|
||||
|
||||
//Application description
|
||||
//ES1 -> ES3 with priority 1
|
||||
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(1));
|
||||
app0->SetAttribute("PCP", UintegerValue(1));
|
||||
n0->AddApplication(app0);
|
||||
app0->SetStartTime(Seconds(0));
|
||||
app0->SetStopTime(Seconds(10));
|
||||
|
||||
//Callback to display the packet latency log
|
||||
std::string context = Names::FindName(n2) + ":" + Names::FindName(net2);
|
||||
net2->TraceConnectWithoutContext("Latency", MakeBoundCallback(&LatencyCallback, context));
|
||||
|
||||
//Callback to write the packet latency hop by hop in a file
|
||||
AsciiTraceHelper asciiTraceHelper;
|
||||
std::string filename = "example.hopByHopLat";
|
||||
Ptr<OutputStreamWrapper> stream = asciiTraceHelper.CreateFileStream(filename);
|
||||
net2->TraceConnectWithoutContext("Latency", MakeBoundCallback(&LatencyHopByHopCallback, stream, context));
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(Seconds(10));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
176
contrib/ethernet/examples/ethernet-switched-withPcap.cc
Normal file
176
contrib/ethernet/examples/ethernet-switched-withPcap.cc
Normal file
@@ -0,0 +1,176 @@
|
||||
#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/ethernet-net-device.h"
|
||||
#include "ns3/ethernet-channel.h"
|
||||
#include "ns3/ethernet-generator.h"
|
||||
#include "ns3/ethernet-header2.h"
|
||||
#include "ns3/switch-net-device.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example of the use of switch-net-device.cc switch-channel.cc
|
||||
* ethernet-net-device.cc ethernet-channel.cc on a network composed of three
|
||||
* end-stations connected with a 1Gb/s full duplex link
|
||||
* ES1 ==== SW ==== ES2
|
||||
* ==== ES3
|
||||
*/
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("Example");
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
//Enable logging
|
||||
LogComponentEnable("Example", LOG_LEVEL_INFO);
|
||||
|
||||
CommandLine cmd(__FILE__);
|
||||
cmd.Parse(argc, argv);
|
||||
|
||||
//Create four nodes
|
||||
Ptr<Node> n0 = CreateObject<Node>();
|
||||
Names::Add("ES1", n0);
|
||||
Ptr<Node> n1 = CreateObject<Node>();
|
||||
Names::Add("ES2", n1);
|
||||
Ptr<Node> n2 = CreateObject<Node>();
|
||||
Names::Add("ES3", n2);
|
||||
Ptr<Node> n3 = CreateObject<Node>();
|
||||
Names::Add("SW", n3);
|
||||
|
||||
//Create and add a netDevice to each end station node
|
||||
Ptr<EthernetNetDevice> net0 = CreateObject<EthernetNetDevice>();
|
||||
n0->AddDevice(net0);
|
||||
Names::Add("ES1#01", net0);
|
||||
Ptr<EthernetNetDevice> net1 = CreateObject<EthernetNetDevice>();
|
||||
n1->AddDevice(net1);
|
||||
Names::Add("ES2#01", net1);
|
||||
Ptr<EthernetNetDevice> net2 = CreateObject<EthernetNetDevice>();
|
||||
n2->AddDevice(net2);
|
||||
Names::Add("ES3#01", net2);
|
||||
|
||||
//Create and add a netDevice to each switch port
|
||||
Ptr<EthernetNetDevice> swnet0 = CreateObject<EthernetNetDevice>();
|
||||
n3->AddDevice(swnet0);
|
||||
Names::Add("SW#01", swnet0);
|
||||
Ptr<EthernetNetDevice> swnet1 = CreateObject<EthernetNetDevice>();
|
||||
n3->AddDevice(swnet1);
|
||||
Names::Add("SW#02", swnet1);
|
||||
Ptr<EthernetNetDevice> swnet2 = CreateObject<EthernetNetDevice>();
|
||||
n3->AddDevice(swnet2);
|
||||
Names::Add("SW#03", swnet2);
|
||||
|
||||
//Create Ethernet Channels and connect switch to the end-stations
|
||||
Ptr<EthernetChannel> channel0 = CreateObject<EthernetChannel>();
|
||||
net0->Attach(channel0);
|
||||
swnet0->Attach(channel0);
|
||||
Ptr<EthernetChannel> channel1 = CreateObject<EthernetChannel>();
|
||||
net1->Attach(channel1);
|
||||
swnet1->Attach(channel1);
|
||||
Ptr<EthernetChannel> channel2 = CreateObject<EthernetChannel>();
|
||||
net2->Attach(channel2);
|
||||
swnet2->Attach(channel2);
|
||||
|
||||
//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(swnet0);
|
||||
sw->AddSwitchPort(swnet1);
|
||||
sw->AddSwitchPort(swnet2);
|
||||
|
||||
//Allocate a Mac address and create 2 FIFOs (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>>());
|
||||
sw->SetAddress(Mac48Address::Allocate());
|
||||
swnet0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
swnet1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
swnet2->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
swnet0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
swnet1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
swnet2->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
|
||||
//Add forwarding table
|
||||
sw->AddForwardingTableEntry(Mac48Address::ConvertFrom(net2->GetAddress()), 1, {swnet2});
|
||||
|
||||
//Application description
|
||||
//ES1 -> ES3 with priority 1
|
||||
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(1));
|
||||
app0->SetAttribute("PCP", UintegerValue(1));
|
||||
n0->AddApplication(app0);
|
||||
app0->SetStartTime(Seconds(0));
|
||||
app0->SetStopTime(Seconds(10));
|
||||
|
||||
//ES2 -> ES1 and ES3 with priority 0
|
||||
Ptr<EthernetGenerator> app1 = CreateObject<EthernetGenerator>();
|
||||
app1->Setup(net1);
|
||||
app1->SetAttribute("Address", AddressValue(Mac48Address("ff:ff:ff:ff:ff:ff")));
|
||||
app1->SetAttribute("BurstSize", UintegerValue(1));
|
||||
app1->SetAttribute("PayloadSize", UintegerValue(1400));
|
||||
app1->SetAttribute("Period", TimeValue(Seconds(2.5)));
|
||||
app1->SetAttribute("VlanID", UintegerValue(2));
|
||||
app1->SetAttribute("PCP", UintegerValue(0));
|
||||
n1->AddApplication(app1);
|
||||
app1->SetStartTime(Seconds(0));
|
||||
app1->SetStopTime(Seconds(5));
|
||||
|
||||
|
||||
//Enable pcap generation
|
||||
PcapHelper pcapHelper;
|
||||
std::string pcapFilename;
|
||||
std::string prefix = "example";
|
||||
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, net1);
|
||||
file = pcapHelper.CreateFile(pcapFilename, std::ios::out, PcapHelper::DLT_EN10MB);
|
||||
pcapHelper.HookDefaultSink<EthernetNetDevice>(net1, "Sniffer", file);
|
||||
|
||||
pcapFilename = pcapHelper.GetFilenameFromDevice(prefix, net2);
|
||||
file = pcapHelper.CreateFile(pcapFilename, std::ios::out, PcapHelper::DLT_EN10MB);
|
||||
pcapHelper.HookDefaultSink<EthernetNetDevice>(net2, "Sniffer", file);
|
||||
|
||||
pcapFilename = pcapHelper.GetFilenameFromDevice(prefix, swnet0);
|
||||
file = pcapHelper.CreateFile(pcapFilename, std::ios::out, PcapHelper::DLT_EN10MB);
|
||||
pcapHelper.HookDefaultSink<EthernetNetDevice>(swnet0, "Sniffer", file);
|
||||
|
||||
pcapFilename = pcapHelper.GetFilenameFromDevice(prefix, swnet1);
|
||||
file = pcapHelper.CreateFile(pcapFilename, std::ios::out, PcapHelper::DLT_EN10MB);
|
||||
pcapHelper.HookDefaultSink<EthernetNetDevice>(swnet1, "Sniffer", file);
|
||||
|
||||
pcapFilename = pcapHelper.GetFilenameFromDevice(prefix, swnet2);
|
||||
file = pcapHelper.CreateFile(pcapFilename, std::ios::out, PcapHelper::DLT_EN10MB);
|
||||
pcapHelper.HookDefaultSink<EthernetNetDevice>(swnet2, "Sniffer", file);
|
||||
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(Seconds(10));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
172
contrib/ethernet/examples/ethernet-switched-withRxTxCallback.cc
Normal file
172
contrib/ethernet/examples/ethernet-switched-withRxTxCallback.cc
Normal file
@@ -0,0 +1,172 @@
|
||||
#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/ethernet-net-device.h"
|
||||
#include "ns3/ethernet-channel.h"
|
||||
#include "ns3/ethernet-generator.h"
|
||||
#include "ns3/ethernet-header2.h"
|
||||
#include "ns3/switch-net-device.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example of the use of switch-net-device.cc switch-channel.cc
|
||||
* ethernet-net-device.cc ethernet-channel.cc on a network composed of three
|
||||
* end-stations connected with a 1Gb/s full duplex link
|
||||
* ES1 ==== SW ==== ES2
|
||||
* ==== ES3
|
||||
*/
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("Example");
|
||||
|
||||
static void
|
||||
MacTxCallback(Ptr<OutputStreamWrapper> stream, std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
Time t = Simulator::Now();
|
||||
Ptr<Packet> originalPacket = p->Copy();
|
||||
EthernetHeader2 ethHeader;
|
||||
originalPacket->RemoveHeader(ethHeader);
|
||||
|
||||
*stream->GetStream() << "NetDevice:" << context << " : At "<< t.GetNanoSeconds() << " FIFO Entry => Packet #"<< p->GetUid() << " from "<< ethHeader.GetSrc() << "(VID:" << ethHeader.GetVid() << ")\n";
|
||||
}
|
||||
|
||||
static void
|
||||
PhyTxBeginCallback(Ptr<OutputStreamWrapper> stream, std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
Time t = Simulator::Now();
|
||||
Ptr<Packet> originalPacket = p->Copy();
|
||||
EthernetHeader2 ethHeader;
|
||||
originalPacket->RemoveHeader(ethHeader);
|
||||
*stream->GetStream() << "NetDevice:" << context << " : At "<< t.GetNanoSeconds() << " FIFO Exit => Packet #"<< p->GetUid() << " from "<< ethHeader.GetSrc() << "(VID:" << ethHeader.GetVid() << ")\n";
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
//Enable logging
|
||||
LogComponentEnable("Example", LOG_LEVEL_INFO);
|
||||
|
||||
CommandLine cmd(__FILE__);
|
||||
cmd.Parse(argc, argv);
|
||||
|
||||
//Create four nodes
|
||||
Ptr<Node> n0 = CreateObject<Node>();
|
||||
Names::Add("ES1", n0);
|
||||
Ptr<Node> n1 = CreateObject<Node>();
|
||||
Names::Add("ES2", n1);
|
||||
Ptr<Node> n2 = CreateObject<Node>();
|
||||
Names::Add("ES3", n2);
|
||||
Ptr<Node> n3 = CreateObject<Node>();
|
||||
Names::Add("SW", n3);
|
||||
|
||||
//Create and add a netDevice to each end station node
|
||||
Ptr<EthernetNetDevice> net0 = CreateObject<EthernetNetDevice>();
|
||||
n0->AddDevice(net0);
|
||||
Names::Add("ES1#01", net0);
|
||||
Ptr<EthernetNetDevice> net1 = CreateObject<EthernetNetDevice>();
|
||||
n1->AddDevice(net1);
|
||||
Names::Add("ES2#01", net1);
|
||||
Ptr<EthernetNetDevice> net2 = CreateObject<EthernetNetDevice>();
|
||||
n2->AddDevice(net2);
|
||||
Names::Add("ES3#01", net2);
|
||||
|
||||
//Create and add a netDevice to each switch port
|
||||
Ptr<EthernetNetDevice> swnet0 = CreateObject<EthernetNetDevice>();
|
||||
n3->AddDevice(swnet0);
|
||||
Names::Add("SW#01", swnet0);
|
||||
Ptr<EthernetNetDevice> swnet1 = CreateObject<EthernetNetDevice>();
|
||||
n3->AddDevice(swnet1);
|
||||
Names::Add("SW#02", swnet1);
|
||||
Ptr<EthernetNetDevice> swnet2 = CreateObject<EthernetNetDevice>();
|
||||
n3->AddDevice(swnet2);
|
||||
Names::Add("SW#03", swnet2);
|
||||
|
||||
//Create Ethernet Channels and connect switch to the end-stations
|
||||
Ptr<EthernetChannel> channel0 = CreateObject<EthernetChannel>();
|
||||
net0->Attach(channel0);
|
||||
swnet0->Attach(channel0);
|
||||
Ptr<EthernetChannel> channel1 = CreateObject<EthernetChannel>();
|
||||
net1->Attach(channel1);
|
||||
swnet1->Attach(channel1);
|
||||
Ptr<EthernetChannel> channel2 = CreateObject<EthernetChannel>();
|
||||
net2->Attach(channel2);
|
||||
swnet2->Attach(channel2);
|
||||
|
||||
//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(swnet0);
|
||||
sw->AddSwitchPort(swnet1);
|
||||
sw->AddSwitchPort(swnet2);
|
||||
|
||||
//Allocate a Mac address and create 2 FIFOs (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>>());
|
||||
sw->SetAddress(Mac48Address::Allocate());
|
||||
swnet0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
swnet1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
swnet2->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
swnet0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
swnet1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
swnet2->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
|
||||
//Add forwarding table
|
||||
sw->AddForwardingTableEntry(Mac48Address::ConvertFrom(net2->GetAddress()), 1, {swnet2});
|
||||
|
||||
//Application description
|
||||
//ES1 -> ES3 with priority 1
|
||||
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(1));
|
||||
app0->SetAttribute("PCP", UintegerValue(1));
|
||||
n0->AddApplication(app0);
|
||||
app0->SetStartTime(Seconds(0));
|
||||
app0->SetStopTime(Seconds(10));
|
||||
|
||||
|
||||
//Callback to wirte FIFO entry and exit event in a file
|
||||
AsciiTraceHelper asciiTraceHelper;
|
||||
std::string filename = "example.fifo";
|
||||
Ptr<OutputStreamWrapper> stream = asciiTraceHelper.CreateFileStream(filename);
|
||||
net0->TraceConnectWithoutContext("MacTx", MakeBoundCallback(&MacTxCallback, stream, Names::FindName(net0)));
|
||||
net0->TraceConnectWithoutContext("PhyTxBegin", MakeBoundCallback(&PhyTxBeginCallback, stream, Names::FindName(net0)));
|
||||
net1->TraceConnectWithoutContext("MacTx", MakeBoundCallback(&MacTxCallback, stream, Names::FindName(net1)));
|
||||
net1->TraceConnectWithoutContext("PhyTxBegin", MakeBoundCallback(&PhyTxBeginCallback, stream, Names::FindName(net1)));
|
||||
net2->TraceConnectWithoutContext("MacTx", MakeBoundCallback(&MacTxCallback, stream, Names::FindName(net2)));
|
||||
net2->TraceConnectWithoutContext("PhyTxBegin", MakeBoundCallback(&PhyTxBeginCallback, stream, Names::FindName(net2)));
|
||||
swnet0->TraceConnectWithoutContext("MacTx", MakeBoundCallback(&MacTxCallback, stream, Names::FindName(swnet0)));
|
||||
swnet0->TraceConnectWithoutContext("PhyTxBegin", MakeBoundCallback(&PhyTxBeginCallback, stream, Names::FindName(swnet0)));
|
||||
swnet1->TraceConnectWithoutContext("MacTx", MakeBoundCallback(&MacTxCallback, stream, Names::FindName(swnet1)));
|
||||
swnet1->TraceConnectWithoutContext("PhyTxBegin", MakeBoundCallback(&PhyTxBeginCallback, stream, Names::FindName(swnet1)));
|
||||
swnet2->TraceConnectWithoutContext("MacTx", MakeBoundCallback(&MacTxCallback, stream, Names::FindName(swnet2)));
|
||||
swnet2->TraceConnectWithoutContext("PhyTxBegin", MakeBoundCallback(&PhyTxBeginCallback, stream, Names::FindName(swnet2)));
|
||||
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(Seconds(10));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
158
contrib/ethernet/examples/ethernet-switched.cc
Normal file
158
contrib/ethernet/examples/ethernet-switched.cc
Normal file
@@ -0,0 +1,158 @@
|
||||
#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/ethernet-net-device.h"
|
||||
#include "ns3/ethernet-channel.h"
|
||||
#include "ns3/ethernet-generator.h"
|
||||
#include "ns3/ethernet-header2.h"
|
||||
#include "ns3/switch-net-device.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example of the use of switch-net-device.cc switch-channel.cc
|
||||
* ethernet-net-device.cc ethernet-channel.cc on a network composed of three
|
||||
* end-stations connected with a 1Gb/s full duplex link
|
||||
* ES1 ==== SW ==== ES2
|
||||
* ==== ES3
|
||||
*/
|
||||
|
||||
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 four nodes
|
||||
Ptr<Node> n0 = CreateObject<Node>();
|
||||
Names::Add("ES1", n0);
|
||||
Ptr<Node> n1 = CreateObject<Node>();
|
||||
Names::Add("ES2", n1);
|
||||
Ptr<Node> n2 = CreateObject<Node>();
|
||||
Names::Add("ES3", n2);
|
||||
Ptr<Node> n3 = CreateObject<Node>();
|
||||
Names::Add("SW", n3);
|
||||
|
||||
//Create and add a netDevice to each end station node
|
||||
Ptr<EthernetNetDevice> net0 = CreateObject<EthernetNetDevice>();
|
||||
n0->AddDevice(net0);
|
||||
Names::Add("ES1#01", net0);
|
||||
Ptr<EthernetNetDevice> net1 = CreateObject<EthernetNetDevice>();
|
||||
n1->AddDevice(net1);
|
||||
Names::Add("ES2#01", net1);
|
||||
Ptr<EthernetNetDevice> net2 = CreateObject<EthernetNetDevice>();
|
||||
n2->AddDevice(net2);
|
||||
Names::Add("ES3#01", net2);
|
||||
|
||||
//Create and add a netDevice to each switch port
|
||||
Ptr<EthernetNetDevice> swnet0 = CreateObject<EthernetNetDevice>();
|
||||
n3->AddDevice(swnet0);
|
||||
Names::Add("SW#01", swnet0);
|
||||
Ptr<EthernetNetDevice> swnet1 = CreateObject<EthernetNetDevice>();
|
||||
n3->AddDevice(swnet1);
|
||||
Names::Add("SW#02", swnet1);
|
||||
Ptr<EthernetNetDevice> swnet2 = CreateObject<EthernetNetDevice>();
|
||||
n3->AddDevice(swnet2);
|
||||
Names::Add("SW#03", swnet2);
|
||||
|
||||
//Create Ethernet Channels and connect switch to the end-stations
|
||||
Ptr<EthernetChannel> channel0 = CreateObject<EthernetChannel>();
|
||||
net0->Attach(channel0);
|
||||
swnet0->Attach(channel0);
|
||||
Ptr<EthernetChannel> channel1 = CreateObject<EthernetChannel>();
|
||||
net1->Attach(channel1);
|
||||
swnet1->Attach(channel1);
|
||||
Ptr<EthernetChannel> channel2 = CreateObject<EthernetChannel>();
|
||||
net2->Attach(channel2);
|
||||
swnet2->Attach(channel2);
|
||||
|
||||
//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(swnet0);
|
||||
sw->AddSwitchPort(swnet1);
|
||||
sw->AddSwitchPort(swnet2);
|
||||
|
||||
//Allocate a Mac address and create 2 FIFOs (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>>());
|
||||
sw->SetAddress(Mac48Address::Allocate());
|
||||
swnet0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
swnet1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
swnet2->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
swnet0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
swnet1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
swnet2->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
|
||||
//Add forwarding table
|
||||
sw->AddForwardingTableEntry(Mac48Address::ConvertFrom(net2->GetAddress()), 1, {swnet2});
|
||||
sw->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 2, {swnet0, swnet2});
|
||||
|
||||
//Application descriptions
|
||||
//ES1 -> ES3 with priority 1
|
||||
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(1));
|
||||
app0->SetAttribute("PCP", UintegerValue(1));
|
||||
n0->AddApplication(app0);
|
||||
app0->SetStartTime(Seconds(0));
|
||||
app0->SetStopTime(Seconds(5));
|
||||
|
||||
//ES2 -> ES1 and ES3 with priority 0
|
||||
Ptr<EthernetGenerator> app1 = CreateObject<EthernetGenerator>();
|
||||
app1->Setup(net1);
|
||||
app1->SetAttribute("Address", AddressValue(Mac48Address("ff:ff:ff:ff:ff:ff")));
|
||||
app1->SetAttribute("BurstSize", UintegerValue(1));
|
||||
app1->SetAttribute("PayloadSize", UintegerValue(1400));
|
||||
app1->SetAttribute("Period", TimeValue(Seconds(2.5)));
|
||||
app1->SetAttribute("VlanID", UintegerValue(2));
|
||||
app1->SetAttribute("PCP", UintegerValue(0));
|
||||
n1->AddApplication(app1);
|
||||
app1->SetStartTime(Seconds(0));
|
||||
app1->SetStopTime(Seconds(5));
|
||||
|
||||
//Callback to display the packet received log
|
||||
std::string context = Names::FindName(n0) + ":" + Names::FindName(net0);
|
||||
net0->TraceConnectWithoutContext("MacRx", MakeBoundCallback(&MacRxCallback, context));
|
||||
context = Names::FindName(n2) + ":" + Names::FindName(net2);
|
||||
net2->TraceConnectWithoutContext("MacRx", MakeBoundCallback(&MacRxCallback, context));
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(Seconds(5));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
137
contrib/ethernet/model/ethernet-channel.cc
Normal file
137
contrib/ethernet/model/ethernet-channel.cc
Normal file
@@ -0,0 +1,137 @@
|
||||
#include "ethernet-channel.h"
|
||||
#include "ethernet-net-device.h"
|
||||
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/packet.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/trace-source-accessor.h"
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("EthernetChannel");
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED(EthernetChannel);
|
||||
|
||||
TypeId
|
||||
EthernetChannel::GetTypeId()
|
||||
{
|
||||
static TypeId tid =
|
||||
TypeId("ns3::EthernetChannel")
|
||||
.SetParent<Channel>()
|
||||
.SetGroupName("Ethernet")
|
||||
.AddConstructor<EthernetChannel>()
|
||||
.AddAttribute("Delay",
|
||||
"Propagation delay through the channel",
|
||||
TimeValue(NanoSeconds(25)),
|
||||
MakeTimeAccessor(&EthernetChannel::m_delay),
|
||||
MakeTimeChecker())
|
||||
.AddTraceSource("TxRxEthernet",
|
||||
"Trace source indicating transmission of packet "
|
||||
"from the EthernetChannel, used by the Animation "
|
||||
"interface.",
|
||||
MakeTraceSourceAccessor(&EthernetChannel::m_txrxEthernet),
|
||||
"ns3::EthernetChannel::TxRxAnimationCallback");
|
||||
return tid;
|
||||
}
|
||||
|
||||
|
||||
EthernetChannel::EthernetChannel()
|
||||
: Channel(),
|
||||
m_nDevices(0)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
}
|
||||
|
||||
void
|
||||
EthernetChannel::Attach(Ptr<EthernetNetDevice> device)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << device);
|
||||
NS_ASSERT_MSG(m_nDevices < N_DEVICES, "Only two devices permitted");
|
||||
NS_ASSERT(device);
|
||||
|
||||
m_wire[m_nDevices++].m_src = device;
|
||||
//
|
||||
// If we have both devices connected to the channel, then finish introducing
|
||||
// the two halves and set the links to IDLE.
|
||||
//
|
||||
if (m_nDevices == N_DEVICES)
|
||||
{
|
||||
m_wire[0].m_dst = m_wire[1].m_src;
|
||||
m_wire[1].m_dst = m_wire[0].m_src;
|
||||
m_wire[0].m_state = IDLE;
|
||||
m_wire[1].m_state = IDLE;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
EthernetChannel::TransmitStart(Ptr<const Packet> p, Ptr<EthernetNetDevice> src, Time txTime)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << p << src);
|
||||
NS_LOG_LOGIC("UID is " << p->GetUid() << ")");
|
||||
|
||||
NS_ASSERT(m_wire[0].m_state != INITIALIZING);
|
||||
NS_ASSERT(m_wire[1].m_state != INITIALIZING);
|
||||
|
||||
uint32_t wire = src == m_wire[0].m_src ? 0 : 1;
|
||||
|
||||
Simulator::ScheduleWithContext(m_wire[wire].m_dst->GetNode()->GetId(),
|
||||
txTime + m_delay,
|
||||
&EthernetNetDevice::Receive,
|
||||
m_wire[wire].m_dst,
|
||||
p->Copy());
|
||||
|
||||
// Call the tx anim callback on the net device
|
||||
m_txrxEthernet(p, src, m_wire[wire].m_dst, txTime, txTime + m_delay);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::size_t
|
||||
EthernetChannel::GetNDevices() const
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
return m_nDevices;
|
||||
}
|
||||
|
||||
Ptr<EthernetNetDevice>
|
||||
EthernetChannel::GetEthernetDevice(std::size_t i) const
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
NS_ASSERT(i < 2);
|
||||
return m_wire[i].m_src;
|
||||
}
|
||||
|
||||
Ptr<NetDevice>
|
||||
EthernetChannel::GetDevice(std::size_t i) const
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
return GetEthernetDevice(i);
|
||||
}
|
||||
|
||||
Time
|
||||
EthernetChannel::GetDelay() const
|
||||
{
|
||||
return m_delay;
|
||||
}
|
||||
|
||||
Ptr<EthernetNetDevice>
|
||||
EthernetChannel::GetSource(uint32_t i) const
|
||||
{
|
||||
return m_wire[i].m_src;
|
||||
}
|
||||
|
||||
Ptr<EthernetNetDevice>
|
||||
EthernetChannel::GetDestination(uint32_t i) const
|
||||
{
|
||||
return m_wire[i].m_dst;
|
||||
}
|
||||
|
||||
bool
|
||||
EthernetChannel::IsInitialized() const
|
||||
{
|
||||
NS_ASSERT(m_wire[0].m_state != INITIALIZING);
|
||||
NS_ASSERT(m_wire[1].m_state != INITIALIZING);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
207
contrib/ethernet/model/ethernet-channel.h
Normal file
207
contrib/ethernet/model/ethernet-channel.h
Normal file
@@ -0,0 +1,207 @@
|
||||
#ifndef ETHERNET_CHANNEL_H
|
||||
#define ETHERNET_CHANNEL_H
|
||||
|
||||
#include "ns3/channel.h"
|
||||
#include "ns3/data-rate.h"
|
||||
#include "ns3/nstime.h"
|
||||
#include "ns3/ptr.h"
|
||||
#include "ns3/traced-callback.h"
|
||||
|
||||
#include <list>
|
||||
|
||||
// Add a doxygen group for this module.
|
||||
// If you have more than one file, this should be in only one of them.
|
||||
/**
|
||||
* \defgroup ethernet Description of the ethernet
|
||||
*/
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
class EthernetNetDevice;
|
||||
class Packet;
|
||||
|
||||
/**
|
||||
* \ingroup ethernet
|
||||
* \brief Simple Ethernet Channel.
|
||||
*
|
||||
* This class represents a very simple full duplex Ethernet channel. It is
|
||||
* largely inspired by the PointToPointChannel. There is no multi-drop
|
||||
* capability on this channel -- there can be a maximum of two Ethernet
|
||||
* net devices connected.
|
||||
*
|
||||
* There are two "wires" in the channel. The first device connected gets the
|
||||
* [0] wire to transmit on. The second device gets the [1] wire. There is a
|
||||
* state (IDLE, TRANSMITTING) associated with each wire.
|
||||
*
|
||||
* \see Attach
|
||||
* \see TransmitStart
|
||||
*/
|
||||
|
||||
class EthernetChannel : public Channel
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \brief Get the TypeId
|
||||
*
|
||||
* \return The TypeId for this class
|
||||
*/
|
||||
static TypeId GetTypeId();
|
||||
|
||||
/**
|
||||
* \brief Create a EthernetChannel
|
||||
*
|
||||
* By default, you get a channel that has a 25ns delay.
|
||||
*/
|
||||
EthernetChannel();
|
||||
|
||||
/**
|
||||
* \brief Attach a given netdevice to this channel
|
||||
* \param device pointer to the netdevice to attach to the channel
|
||||
*/
|
||||
void Attach(Ptr<EthernetNetDevice> device);
|
||||
|
||||
/**
|
||||
* \brief Transmit a packet over this channel
|
||||
* \param p Packet to transmit
|
||||
* \param src Source EthernetNetDevice
|
||||
* \param txTime Transmit time to apply
|
||||
* \returns true if successful (currently always true)
|
||||
*/
|
||||
virtual bool TransmitStart(Ptr<const Packet> p, Ptr<EthernetNetDevice> src, Time txTime);
|
||||
|
||||
/**
|
||||
* \brief Get number of devices on this channel
|
||||
* \returns number of devices on this channel
|
||||
*/
|
||||
std::size_t GetNDevices() const override;
|
||||
|
||||
/**
|
||||
* \brief Get EthernetNetDevice corresponding to index i on this channel
|
||||
* \param i Index number of the device requested
|
||||
* \returns Ptr to EthernetNetDevice requested
|
||||
*/
|
||||
Ptr<EthernetNetDevice> GetEthernetDevice(std::size_t i) const;
|
||||
|
||||
/**
|
||||
* \brief Get NetDevice corresponding to index i on this channel
|
||||
* \param i Index number of the device requested
|
||||
* \returns Ptr to NetDevice requested
|
||||
*/
|
||||
Ptr<NetDevice> GetDevice(std::size_t i) const override;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* \brief Get the delay associated with this channel
|
||||
* \returns Time delay
|
||||
*/
|
||||
Time GetDelay() const;
|
||||
|
||||
/**
|
||||
* \brief Check to make sure the wire is initialized
|
||||
* \returns true if initialized, asserts otherwise
|
||||
*/
|
||||
bool IsInitialized() const;
|
||||
|
||||
/**
|
||||
* \brief Get the net-device source
|
||||
* \param i the wire requested
|
||||
* \returns Ptr to EthernetNetDevice source for the
|
||||
* specified wire
|
||||
*/
|
||||
Ptr<EthernetNetDevice> GetSource(uint32_t i) const;
|
||||
|
||||
/**
|
||||
* \brief Get the net-device destination
|
||||
* \param i the wire requested
|
||||
* \returns Ptr to EthernetNetDevice destination for
|
||||
* the specified wire
|
||||
*/
|
||||
Ptr<EthernetNetDevice> GetDestination(uint32_t i) const;
|
||||
|
||||
/**
|
||||
* TracedCallback signature for packet transmission animation events.
|
||||
*
|
||||
* \param [in] packet The packet being transmitted.
|
||||
* \param [in] txDevice the TransmitTing NetDevice.
|
||||
* \param [in] rxDevice the Receiving NetDevice.
|
||||
* \param [in] duration The amount of time to transmit the packet.
|
||||
* \param [in] lastBitTime Last bit receive time (relative to now)
|
||||
* \deprecated The non-const \c Ptr<NetDevice> argument is deprecated
|
||||
* and will be changed to \c Ptr<const NetDevice> in a future release.
|
||||
*/
|
||||
typedef void (*TxRxAnimationCallback)(Ptr<const Packet> packet,
|
||||
Ptr<NetDevice> txDevice,
|
||||
Ptr<NetDevice> rxDevice,
|
||||
Time duration,
|
||||
Time lastBitTime);
|
||||
|
||||
private:
|
||||
/** Each ethernet full duplex wire has exactly two net devices. */
|
||||
static const std::size_t N_DEVICES = 2;
|
||||
|
||||
Time m_delay; //!< Propagation delay
|
||||
std::size_t m_nDevices; //!< Devices of this channel
|
||||
|
||||
/**
|
||||
* The trace source for the packet transmission animation events that the
|
||||
* device can fire.
|
||||
* Arguments to the callback are the packet, transmitting
|
||||
* net device, receiving net device, transmission time and
|
||||
* packet receipt time.
|
||||
*
|
||||
* \see class CallBackTraceSource
|
||||
* \deprecated The non-const \c Ptr<NetDevice> argument is deprecated
|
||||
* and will be changed to \c Ptr<const NetDevice> in a future release.
|
||||
*/
|
||||
TracedCallback<Ptr<const Packet>, // Packet being transmitted
|
||||
Ptr<NetDevice>, // Transmitting NetDevice
|
||||
Ptr<NetDevice>, // Receiving NetDevice
|
||||
Time, // Amount of time to transmit the pkt
|
||||
Time // Last bit receive time (relative to now)
|
||||
>
|
||||
m_txrxEthernet;
|
||||
|
||||
/** \brief Wire states
|
||||
*
|
||||
*/
|
||||
enum WireState
|
||||
{
|
||||
/** Initializing state */
|
||||
INITIALIZING,
|
||||
/** Idle state (no transmission from NetDevice) */
|
||||
IDLE,
|
||||
/** Transmitting state (data being transmitted from NetDevice. */
|
||||
TRANSMITTING,
|
||||
/** Propagating state (data is being propagated in the channel. */
|
||||
PROPAGATING
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Wire model for the EthernetChannel
|
||||
*/
|
||||
class Wire
|
||||
{
|
||||
public:
|
||||
/** \brief Create the wire, it will be in INITIALIZING state
|
||||
*
|
||||
*/
|
||||
Wire()
|
||||
: m_state(INITIALIZING),
|
||||
m_src(nullptr),
|
||||
m_dst(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
WireState m_state; //!< State of the wire
|
||||
Ptr<EthernetNetDevice> m_src; //!< First NetDevice
|
||||
Ptr<EthernetNetDevice> m_dst; //!< Second NetDevice
|
||||
};
|
||||
|
||||
Wire m_wire[N_DEVICES]; //!< Wire model
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* ETHERNET_CHANNEL_H */
|
||||
277
contrib/ethernet/model/ethernet-header2.cc
Normal file
277
contrib/ethernet/model/ethernet-header2.cc
Normal file
@@ -0,0 +1,277 @@
|
||||
#include "ethernet-header2.h"
|
||||
|
||||
#include "ns3/abort.h"
|
||||
#include "ns3/assert.h"
|
||||
#include "ns3/header.h"
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/mac48-address.h"
|
||||
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
|
||||
#include "ns3/address-utils.h"
|
||||
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("EthernetHeader2");
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED(EthernetHeader2);
|
||||
|
||||
EthernetHeader2::EthernetHeader2()
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
}
|
||||
|
||||
EthernetHeader2::~EthernetHeader2()
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
}
|
||||
|
||||
TypeId
|
||||
EthernetHeader2::GetTypeId()
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
static TypeId tid = TypeId("ns3::EthernetHeader2")
|
||||
.SetParent<Header>()
|
||||
.SetGroupName("Ethernet")
|
||||
.AddConstructor<EthernetHeader2>();
|
||||
return tid;
|
||||
}
|
||||
|
||||
TypeId
|
||||
EthernetHeader2::GetInstanceTypeId() const
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
return GetTypeId();
|
||||
}
|
||||
|
||||
void
|
||||
EthernetHeader2::Print(std::ostream& os) const
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
std::string proto;
|
||||
|
||||
os << m_src << "->" << m_dest << " with ";
|
||||
for(int i=0; i<(int)m_QTagList.size(); i++)
|
||||
{
|
||||
if(m_QTagList[i].Type == VLAN)
|
||||
{
|
||||
os <<"vlan_id=" << (m_QTagList[i].TCI & 0xFFF) << " ";
|
||||
}
|
||||
if(m_QTagList[i].Type == REDUNDANCY)
|
||||
{
|
||||
os <<"RTAG=True ";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t
|
||||
EthernetHeader2::GetSerializedSize() const
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
int tagSize = 0;
|
||||
for (int i=0; i<(int)m_QTagList.size(); i++)
|
||||
{
|
||||
if(m_QTagList[i].Type==VLAN)
|
||||
{
|
||||
tagSize += 4;
|
||||
}
|
||||
else if(m_QTagList[i].Type==REDUNDANCY)
|
||||
{
|
||||
tagSize += 6;
|
||||
}
|
||||
}
|
||||
return 6 + 6 + tagSize + 2;
|
||||
}
|
||||
|
||||
void
|
||||
EthernetHeader2::Serialize(Buffer::Iterator start) const
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
Buffer::Iterator i = start;
|
||||
WriteTo(i, m_dest);
|
||||
WriteTo(i, m_src);
|
||||
|
||||
for (int j=0; j<(int)m_QTagList.size() ; j++)
|
||||
{
|
||||
i.WriteHtonU16(m_QTagList[j].TPID);
|
||||
if(m_QTagList[j].Type == VLAN)
|
||||
{
|
||||
i.WriteHtonU16(m_QTagList[j].TCI);
|
||||
}
|
||||
else if(m_QTagList[j].Type == REDUNDANCY)
|
||||
{
|
||||
i.WriteHtonU32(m_QTagList[j].TCI);
|
||||
}
|
||||
}
|
||||
i.WriteHtonU16(m_ethertype);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
EthernetHeader2::Deserialize(Buffer::Iterator start)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
|
||||
Buffer::Iterator i = start;
|
||||
ReadFrom(i, m_dest);
|
||||
ReadFrom(i, m_src);
|
||||
uint16_t tmp = i.ReadNtohU16();
|
||||
while (tmp==0x8100 or tmp==0xf1c1){
|
||||
TagType type = VLAN;
|
||||
uint32_t tci = 0;
|
||||
|
||||
if (tmp==0x8100){
|
||||
type = VLAN;
|
||||
tci = i.ReadNtohU16();
|
||||
}
|
||||
else if (tmp==0xf1c1){
|
||||
type = REDUNDANCY;
|
||||
tci = i.ReadNtohU32();
|
||||
}
|
||||
Qtag entry = {tmp, tci, type};
|
||||
m_QTagList.insert(m_QTagList.end(), entry);
|
||||
tmp = i.ReadNtohU16();
|
||||
}
|
||||
m_ethertype = tmp;
|
||||
|
||||
// NS_LOG_INFO("m_QTagList size = " << m_QTagList.size());
|
||||
return GetSerializedSize();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
EthernetHeader2::SetDest(Mac48Address addr)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
m_dest = addr;
|
||||
}
|
||||
|
||||
Mac48Address
|
||||
EthernetHeader2::GetDest()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
return m_dest;
|
||||
}
|
||||
|
||||
void
|
||||
EthernetHeader2::SetSrc(Mac48Address addr)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
m_src = addr;
|
||||
}
|
||||
|
||||
Mac48Address
|
||||
EthernetHeader2::GetSrc()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
return m_src;
|
||||
}
|
||||
|
||||
|
||||
uint8_t
|
||||
EthernetHeader2::GetPcp()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
for(int i=0; i<(int)m_QTagList.size(); i++)
|
||||
{
|
||||
if(m_QTagList[i].Type == VLAN)
|
||||
{
|
||||
return (m_QTagList[i].TCI >> 13) & 0x7;
|
||||
}
|
||||
}
|
||||
NS_ASSERT_MSG(true, "Can't find a Vlan QTag in this header");
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
EthernetHeader2::GetDei()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
for(int i=0; i<(int)m_QTagList.size(); i++)
|
||||
{
|
||||
if(m_QTagList[i].Type == VLAN)
|
||||
{
|
||||
return uint8_t((m_QTagList[i].TCI >> 12) & 0x1);
|
||||
}
|
||||
}
|
||||
NS_ASSERT_MSG(true, "Can't find a Vlan QTag in this header");
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
EthernetHeader2::GetVid()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
for(int i=0; i<(int)m_QTagList.size(); i++)
|
||||
{
|
||||
if(m_QTagList[i].Type == VLAN)
|
||||
{
|
||||
return (m_QTagList[i].TCI & 0xFFF);
|
||||
}
|
||||
}
|
||||
NS_ASSERT_MSG(true, "Can't find a Vlan QTag in this header");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
EthernetHeader2::SetEthertype(uint16_t ethertype)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
m_ethertype = ethertype;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
EthernetHeader2::GetEthertype()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
return m_ethertype;
|
||||
}
|
||||
|
||||
void
|
||||
EthernetHeader2::SetVlanTag(uint8_t pcp, uint8_t dei, uint16_t vid)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
NS_ASSERT_MSG(vid < 4096 , "Vlan id must be between 0 and 4095");
|
||||
NS_ASSERT_MSG(dei < 2 , "DEI must be between 0 and 1");
|
||||
NS_ASSERT_MSG(pcp < 8 , "PCP must be between 0 and 7");
|
||||
|
||||
uint16_t tpid = 0x8100;
|
||||
uint32_t tci = (pcp << 13) | (dei << 12) | vid;
|
||||
Qtag entry = {tpid, tci, VLAN};
|
||||
m_QTagList.insert(m_QTagList.begin(), entry);
|
||||
}
|
||||
|
||||
void
|
||||
EthernetHeader2::SetRedundancyTag(uint16_t seqNum)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
uint16_t tpid = 0xf1c1;
|
||||
uint32_t tci = (0 << 16) | seqNum;
|
||||
Qtag entry = {tpid, tci, REDUNDANCY};
|
||||
m_QTagList.insert(m_QTagList.begin(), entry);
|
||||
}
|
||||
|
||||
uint16_t
|
||||
EthernetHeader2::RemoveRedundancyTag()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
for (int i=0; i<(int)m_QTagList.size(); i++)
|
||||
{
|
||||
if(m_QTagList[i].Type == REDUNDANCY)
|
||||
{
|
||||
uint16_t seqNum = m_QTagList[i].TCI & 0xFFFF;
|
||||
m_QTagList.erase(m_QTagList.begin() + i);
|
||||
return seqNum;
|
||||
}
|
||||
}
|
||||
|
||||
NS_ASSERT_MSG(true, "Can't find a Redundancy QTag in this header");
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
86
contrib/ethernet/model/ethernet-header2.h
Normal file
86
contrib/ethernet/model/ethernet-header2.h
Normal file
@@ -0,0 +1,86 @@
|
||||
#ifndef ETHERNET_HEADER2_H
|
||||
#define ETHERNET_HEADER2_H
|
||||
|
||||
#include "ns3/header.h"
|
||||
#include "ns3/mac48-address.h"
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
/**
|
||||
* \ingroup ethernet
|
||||
* \brief Packet header for Ethernet
|
||||
*
|
||||
* This class can be used to add a header to Ethernet packet.
|
||||
*/
|
||||
|
||||
class EthernetHeader2 : public Header
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \brief Construct a Ethernet header.
|
||||
*/
|
||||
EthernetHeader2();
|
||||
|
||||
/**
|
||||
* \brief Destroy a Ethernet header.
|
||||
*/
|
||||
~EthernetHeader2() override;
|
||||
|
||||
/**
|
||||
* \brief Get the TypeId
|
||||
*
|
||||
* \return The TypeId for this class
|
||||
*/
|
||||
static TypeId GetTypeId();
|
||||
|
||||
/**
|
||||
* \brief Get the TypeId of the instance
|
||||
*
|
||||
* \return The TypeId for this instance
|
||||
*/
|
||||
TypeId GetInstanceTypeId() const override;
|
||||
|
||||
void Print(std::ostream& os) const override;
|
||||
void Serialize(Buffer::Iterator start) const override;
|
||||
uint32_t Deserialize(Buffer::Iterator start) override;
|
||||
uint32_t GetSerializedSize() const override;
|
||||
|
||||
void SetDest(Mac48Address addr);
|
||||
Mac48Address GetDest();
|
||||
void SetSrc(Mac48Address addr);
|
||||
Mac48Address GetSrc();
|
||||
uint8_t GetPcp();
|
||||
uint8_t GetDei();
|
||||
uint16_t GetVid();
|
||||
void SetEthertype(uint16_t ethertype);
|
||||
uint16_t GetEthertype();
|
||||
|
||||
void SetVlanTag(uint8_t pcp, uint8_t dei, uint16_t vid);
|
||||
void SetRedundancyTag(uint16_t seqNum);
|
||||
uint16_t RemoveRedundancyTag();
|
||||
|
||||
|
||||
private:
|
||||
Mac48Address m_dest;
|
||||
Mac48Address m_src;
|
||||
|
||||
//QTag (VlanTag, RedundancyTag ...)
|
||||
enum TagType
|
||||
{
|
||||
VLAN,
|
||||
REDUNDANCY,
|
||||
};
|
||||
struct Qtag
|
||||
{
|
||||
uint16_t TPID; //Tag Protocol Identifier
|
||||
uint32_t TCI; //Tag Control Information
|
||||
TagType Type;
|
||||
};
|
||||
|
||||
std::vector<Qtag> m_QTagList;
|
||||
|
||||
uint16_t m_ethertype;
|
||||
};
|
||||
|
||||
} // namespace eden
|
||||
#endif /* ETHERNET_HEADER2_H */
|
||||
769
contrib/ethernet/model/ethernet-net-device.cc
Normal file
769
contrib/ethernet/model/ethernet-net-device.cc
Normal file
@@ -0,0 +1,769 @@
|
||||
#include "ethernet-net-device.h"
|
||||
|
||||
#include "ethernet-channel.h"
|
||||
#include "ethernet-header2.h"
|
||||
|
||||
#include "ns3/error-model.h"
|
||||
#include "ns3/llc-snap-header.h"
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/mac48-address.h"
|
||||
#include "ns3/pointer.h"
|
||||
#include "ns3/queue.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/trace-source-accessor.h"
|
||||
#include "ns3/uinteger.h"
|
||||
#include "ns3/ethernet-trailer.h"
|
||||
#include "ns3/timestamp-tag.h"
|
||||
#include "ns3/names.h"
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("EthernetNetDevice");
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED(EthernetNetDevice);
|
||||
|
||||
TypeId
|
||||
EthernetNetDevice::GetTypeId()
|
||||
{
|
||||
static TypeId tid =
|
||||
TypeId("ns3::EthernetNetDevice")
|
||||
.SetParent<NetDevice>()
|
||||
.SetGroupName("Ethernet")
|
||||
.AddConstructor<EthernetNetDevice>()
|
||||
.AddAttribute("Mtu",
|
||||
"The MAC-level Maximum Transmission Unit",
|
||||
UintegerValue(DEFAULT_MTU),
|
||||
MakeUintegerAccessor(&EthernetNetDevice::SetMtu,
|
||||
&EthernetNetDevice::GetMtu),
|
||||
MakeUintegerChecker<uint16_t>())
|
||||
.AddAttribute("Address",
|
||||
"The MAC address of this device.",
|
||||
Mac48AddressValue(Mac48Address("00:00:00:00:ED:E1")),
|
||||
MakeMac48AddressAccessor(&EthernetNetDevice::m_address),
|
||||
MakeMac48AddressChecker())
|
||||
.AddAttribute("DataRate",
|
||||
"The default data rate for point to point links",
|
||||
DataRateValue(DataRate("1Gb/s")),
|
||||
MakeDataRateAccessor(&EthernetNetDevice::m_bps),
|
||||
MakeDataRateChecker())
|
||||
.AddAttribute("ReceiveErrorModel",
|
||||
"The receiver error model used to simulate packet loss",
|
||||
PointerValue(),
|
||||
MakePointerAccessor(&EthernetNetDevice::m_receiveErrorModel),
|
||||
MakePointerChecker<ErrorModel>())
|
||||
.AddAttribute("preambleAndSFDGap",
|
||||
"Number of byte for the preamble and start of frame delimiter gap",
|
||||
UintegerValue(8),
|
||||
MakeUintegerAccessor(&EthernetNetDevice::m_preambleAndSFDGap),
|
||||
MakeUintegerChecker<uint8_t>())
|
||||
.AddAttribute("InterframeGap",
|
||||
"Number of byte for the interframe gap",
|
||||
UintegerValue(12),
|
||||
MakeUintegerAccessor(&EthernetNetDevice::m_interframeGap),
|
||||
MakeUintegerChecker<uint8_t>())
|
||||
|
||||
//
|
||||
// Trace sources at the "top" of the net device, where packets transition
|
||||
// to/from higher layers.
|
||||
//
|
||||
.AddTraceSource("MacTx",
|
||||
"Trace source indicating a packet has arrived "
|
||||
"for transmission by this device",
|
||||
MakeTraceSourceAccessor(&EthernetNetDevice::m_macTxTrace),
|
||||
"ns3::Packet::TracedCallback")
|
||||
.AddTraceSource("MacTxAnimation",
|
||||
"Trace source indicating a packet has arrived "
|
||||
"for transmission by this device",
|
||||
MakeTraceSourceAccessor(&EthernetNetDevice::m_macTxAnimationTrace),
|
||||
"ns3::EthernetNetDevice::MacTxAnimationCallback")
|
||||
.AddTraceSource("MacTxDrop",
|
||||
"Trace source indicating a packet has been dropped "
|
||||
"by the device before transmission",
|
||||
MakeTraceSourceAccessor(&EthernetNetDevice::m_macTxDropTrace),
|
||||
"ns3::Packet::TracedCallback")
|
||||
.AddTraceSource("MacPromiscRx",
|
||||
"A packet has been received by this device, "
|
||||
"has been passed up from the physical layer "
|
||||
"and is being forwarded up the local protocol stack. "
|
||||
"This is a promiscuous trace,",
|
||||
MakeTraceSourceAccessor(&EthernetNetDevice::m_macPromiscRxTrace),
|
||||
"ns3::Packet::TracedCallback")
|
||||
.AddTraceSource("MacRx",
|
||||
"A packet has been received by this device, "
|
||||
"has been passed up from the physical layer "
|
||||
"and is being forwarded up the local protocol stack. "
|
||||
"This is a non-promiscuous trace,",
|
||||
MakeTraceSourceAccessor(&EthernetNetDevice::m_macRxTrace),
|
||||
"ns3::Packet::TracedCallback")
|
||||
.AddTraceSource("MacRxAnimation",
|
||||
"Trace source indicating a packet has arrived "
|
||||
"in this device",
|
||||
MakeTraceSourceAccessor(&EthernetNetDevice::m_macRxAnimationTrace),
|
||||
"ns3::EthernetNetDevice::MacRxAnimationCallback")
|
||||
#if 0
|
||||
// Not currently implemented for this device
|
||||
.AddTraceSource ("MacRxDrop",
|
||||
"Trace source indicating a packet was dropped "
|
||||
"before being forwarded up the stack",
|
||||
MakeTraceSourceAccessor (&EthernetNetDevice::m_macRxDropTrace),
|
||||
"ns3::Packet::TracedCallback")
|
||||
#endif
|
||||
//
|
||||
// Trace sources at the "bottom" of the net device, where packets transition
|
||||
// to/from the channel.
|
||||
//
|
||||
.AddTraceSource("PhyTxBegin",
|
||||
"Trace source indicating a packet has begun "
|
||||
"transmitting over the channel",
|
||||
MakeTraceSourceAccessor(&EthernetNetDevice::m_phyTxBeginTrace),
|
||||
"ns3::Packet::TracedCallback")
|
||||
.AddTraceSource("PhyTxEnd",
|
||||
"Trace source indicating a packet has been "
|
||||
"completely transmitted over the channel",
|
||||
MakeTraceSourceAccessor(&EthernetNetDevice::m_phyTxEndTrace),
|
||||
"ns3::Packet::TracedCallback")
|
||||
.AddTraceSource("PhyTxDrop",
|
||||
"Trace source indicating a packet has been "
|
||||
"dropped by the device during transmission",
|
||||
MakeTraceSourceAccessor(&EthernetNetDevice::m_phyTxDropTrace),
|
||||
"ns3::Packet::TracedCallback")
|
||||
.AddTraceSource("Latency",
|
||||
"Trace source to compute network latency ",
|
||||
MakeTraceSourceAccessor(&EthernetNetDevice::m_latencyTrace),
|
||||
"ns3::Packet::TracedCallback")
|
||||
.AddTraceSource("FIFOState",
|
||||
"Trace source to study the FIFO state ",
|
||||
MakeTraceSourceAccessor(&EthernetNetDevice::m_FIFOStateSnifferTrace),
|
||||
"ns3::EthernetNetDevice::m_FIFOStateSnifferTrace")
|
||||
#if 0
|
||||
// Not currently implemented for this device
|
||||
.AddTraceSource ("PhyRxBegin",
|
||||
"Trace source indicating a packet has begun "
|
||||
"being received by the device",
|
||||
MakeTraceSourceAccessor (&EthernetNetDevice::m_phyRxBeginTrace),
|
||||
"ns3::Packet::TracedCallback")
|
||||
#endif
|
||||
.AddTraceSource("PhyRxEnd",
|
||||
"Trace source indicating a packet has been "
|
||||
"completely received by the device",
|
||||
MakeTraceSourceAccessor(&EthernetNetDevice::m_phyRxEndTrace),
|
||||
"ns3::Packet::TracedCallback")
|
||||
.AddTraceSource("PhyRxDrop",
|
||||
"Trace source indicating a packet has been "
|
||||
"dropped by the device during reception",
|
||||
MakeTraceSourceAccessor(&EthernetNetDevice::m_phyRxDropTrace),
|
||||
"ns3::Packet::TracedCallback")
|
||||
|
||||
//
|
||||
// Trace sources designed to simulate a packet sniffer facility (tcpdump).
|
||||
// Note that there is really no difference between promiscuous and
|
||||
// non-promiscuous traces in a point-to-point link.
|
||||
//
|
||||
.AddTraceSource("Sniffer",
|
||||
"Trace source simulating a non-promiscuous packet sniffer "
|
||||
"attached to the device",
|
||||
MakeTraceSourceAccessor(&EthernetNetDevice::m_snifferTrace),
|
||||
"ns3::Packet::TracedCallback")
|
||||
.AddTraceSource("PromiscSniffer",
|
||||
"Trace source simulating a promiscuous packet sniffer "
|
||||
"attached to the device",
|
||||
MakeTraceSourceAccessor(&EthernetNetDevice::m_promiscSnifferTrace),
|
||||
"ns3::Packet::TracedCallback");
|
||||
return tid;
|
||||
}
|
||||
|
||||
EthernetNetDevice::EthernetNetDevice()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
m_txMachineState = READY;
|
||||
m_channel = nullptr;
|
||||
m_linkUp = false;
|
||||
m_currentPkt = nullptr;
|
||||
}
|
||||
|
||||
EthernetNetDevice::~EthernetNetDevice()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
}
|
||||
|
||||
void
|
||||
EthernetNetDevice::AddHeader(Ptr<Packet> p, Mac48Address dst, Mac48Address src, uint16_t ethertype)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
EthernetHeader2 ethHeader;
|
||||
ethHeader.SetDest(dst);
|
||||
ethHeader.SetSrc(src);
|
||||
ethHeader.SetEthertype(ethertype);
|
||||
p->AddHeader(ethHeader);
|
||||
}
|
||||
|
||||
void
|
||||
EthernetNetDevice::AddHeader(Ptr<Packet> p, Mac48Address dst, Mac48Address src, uint16_t ethertype, uint16_t vid, uint8_t pcp, uint8_t dei)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
EthernetHeader2 ethHeader;
|
||||
ethHeader.SetDest(dst);
|
||||
ethHeader.SetSrc(src);
|
||||
ethHeader.SetEthertype(ethertype);
|
||||
ethHeader.SetVlanTag(pcp, dei, vid);
|
||||
p->AddHeader(ethHeader);
|
||||
}
|
||||
|
||||
void
|
||||
EthernetNetDevice::DoDispose()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
m_node = nullptr;
|
||||
m_channel = nullptr;
|
||||
m_receiveErrorModel = nullptr;
|
||||
m_currentPkt = nullptr;
|
||||
m_queues.clear();
|
||||
NetDevice::DoDispose();
|
||||
}
|
||||
|
||||
void
|
||||
EthernetNetDevice::SetDataRate(DataRate bps)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
m_bps = bps;
|
||||
}
|
||||
|
||||
bool
|
||||
EthernetNetDevice::TransmitStart(Ptr<Packet> p)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << p);
|
||||
NS_ASSERT_MSG(m_channel != nullptr, "Channel ptr is null");
|
||||
|
||||
NS_LOG_INFO(Names::FindName(this) << " PKT #" << p->GetUid() << " at " << Simulator::Now().GetNanoSeconds()<<" Transmit started ");
|
||||
|
||||
//Add a tag to compute delay between reception(or FIFO enter if first
|
||||
//emission port) and transmission start
|
||||
TimestampTag tag(Simulator::Now());
|
||||
p->AddByteTag(tag);
|
||||
|
||||
//
|
||||
// This function is called to start the process of transmitting a packet.
|
||||
// We need to tell the channel that we've started wiggling the wire and
|
||||
// schedule an event that will be executed when the transmission is complete.
|
||||
//
|
||||
NS_ASSERT_MSG(m_txMachineState == READY, "Must be READY to transmit");
|
||||
m_txMachineState = BUSY;
|
||||
m_currentPkt = p;
|
||||
m_phyTxBeginTrace(m_currentPkt);
|
||||
|
||||
Time preambleAndSFDGapTime = m_bps.CalculateBytesTxTime(m_preambleAndSFDGap);
|
||||
Time txTime = m_bps.CalculateBytesTxTime(p->GetSize());
|
||||
Time interpacketGapTime = m_bps.CalculateBytesTxTime(m_interframeGap);
|
||||
Time txCompleteTime = preambleAndSFDGapTime + txTime + interpacketGapTime;
|
||||
|
||||
//NS_LOG_INFO(Names::FindName(this) << " "<< Simulator::Now().GetNanoSeconds()<<" Transmit pkt #"<<p->GetUid());
|
||||
//NS_LOG_LOGIC(Names::FindName(this) << " Schedule TransmitCompleteEvent in " << txCompleteTime.As(Time::S) << " for PKT #" << p->GetUid());
|
||||
Simulator::Schedule(txCompleteTime, &EthernetNetDevice::TransmitComplete, this);
|
||||
|
||||
bool result = m_channel->TransmitStart(p, this, txCompleteTime-interpacketGapTime); //Pkt don't need to wait for the end of Interpacket gap to be considered as receive on the other end of the link
|
||||
if (!result)
|
||||
{
|
||||
m_phyTxDropTrace(p);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
EthernetNetDevice::TransmitComplete()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
|
||||
NS_LOG_INFO(Names::FindName(this) << " PKT #" << m_currentPkt->GetUid() << " at " << Simulator::Now().GetNanoSeconds()<<" Transmit completed ");
|
||||
// NS_LOG_INFO(Names::FindName(this) << " "<< Simulator::Now().GetNanoSeconds()<<" Transmit completed pkt ");
|
||||
//
|
||||
// This function is called to when we're all done transmitting a packet.
|
||||
// We try and pull another packet off of the transmit queue. If the queue
|
||||
// is empty, we are done, otherwise we need to start transmitting the
|
||||
// next packet.
|
||||
//
|
||||
NS_ASSERT_MSG(m_txMachineState == BUSY, "Must be BUSY if transmitting");
|
||||
m_txMachineState = READY;
|
||||
|
||||
NS_ASSERT_MSG(m_currentPkt, "EthernetNetDevice::TransmitComplete(): m_currentPkt zero");
|
||||
|
||||
m_phyTxEndTrace(m_currentPkt);
|
||||
|
||||
m_currentPkt = nullptr;
|
||||
|
||||
//Add the event after all the already present at this exact instant to avoid
|
||||
//the beginning of a transmission if a packet will be ready at the event just
|
||||
//after but at the same time instant.
|
||||
Simulator::Schedule(Time(0), &EthernetNetDevice::CheckForReadyPacket, this);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
EthernetNetDevice::CheckForReadyPacket()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
if (m_txMachineState != READY){
|
||||
return;
|
||||
}
|
||||
|
||||
int next_queue_id = TransmitSelection();
|
||||
if(next_queue_id==-1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Ptr<Packet> p = m_queues[next_queue_id]->Dequeue();
|
||||
//
|
||||
// Got another packet off of the queue, so start the transmit process again.
|
||||
//
|
||||
m_snifferTrace(p);
|
||||
m_promiscSnifferTrace(p);
|
||||
TransmitStart(p);
|
||||
|
||||
}
|
||||
|
||||
int
|
||||
EthernetNetDevice::TransmitSelection()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
|
||||
//For now simple Static Priority Algo
|
||||
for (int i = m_queues.size(); i --> 0; )
|
||||
{
|
||||
if(!m_queues[i]->IsEmpty())
|
||||
{
|
||||
return(i);
|
||||
}
|
||||
}
|
||||
|
||||
return(-1);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
EthernetNetDevice::Attach(Ptr<EthernetChannel> ch)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << &ch);
|
||||
|
||||
m_channel = ch;
|
||||
|
||||
m_channel->Attach(this);
|
||||
|
||||
//
|
||||
// This device is up whenever it is attached to a channel. A better plan
|
||||
// would be to have the link come up when both devices are attached, but this
|
||||
// is not done for now.
|
||||
//
|
||||
NotifyLinkUp();
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
EthernetNetDevice::SetQueue(Ptr<Queue<Packet>> q)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << q);
|
||||
m_queues.insert(m_queues.end(),q);
|
||||
}
|
||||
|
||||
void
|
||||
EthernetNetDevice::SetReceiveErrorModel(Ptr<ErrorModel> em)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << em);
|
||||
m_receiveErrorModel = em;
|
||||
}
|
||||
|
||||
void
|
||||
EthernetNetDevice::Receive(Ptr<Packet> packet)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << packet);
|
||||
NS_LOG_LOGIC("UID is " << packet->GetUid());
|
||||
if (m_receiveErrorModel && m_receiveErrorModel->IsCorrupt(packet))
|
||||
{
|
||||
//
|
||||
// If we have an error model and it indicates that it is time to lose a
|
||||
// corrupted packet, don't forward this packet up, let it go.
|
||||
//
|
||||
NS_LOG_LOGIC("Dropping pkt due to error model ");
|
||||
m_phyRxDropTrace(packet);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Add timestamp to measure delay in the switches
|
||||
TimestampTag tag(Simulator::Now());
|
||||
packet->AddByteTag(tag);
|
||||
//
|
||||
// Hit the trace hooks. All of these hooks are in the same place in this
|
||||
// device because it is so simple, but this is not usually the case in
|
||||
// more complicated devices.
|
||||
//
|
||||
m_snifferTrace(packet);
|
||||
m_promiscSnifferTrace(packet);
|
||||
m_phyRxEndTrace(packet);
|
||||
|
||||
//
|
||||
// Trace sinks will expect complete packets, not packets without some of the
|
||||
// headers.
|
||||
//
|
||||
Ptr<Packet> originalPacket = packet->Copy();
|
||||
|
||||
EthernetTrailer trailer;
|
||||
packet->RemoveTrailer(trailer);
|
||||
if (Node::ChecksumEnabled())
|
||||
{
|
||||
trailer.EnableFcs(true);
|
||||
}
|
||||
|
||||
bool crcGood = trailer.CheckFcs(packet);
|
||||
if (!crcGood)
|
||||
{
|
||||
NS_LOG_INFO("CRC error on Packet " << packet);
|
||||
m_phyRxDropTrace(packet);
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Strip off the ethernet protocol header and forward this packet
|
||||
// up the protocol stack. Since this is a simple point-to-point link,
|
||||
// there is no difference in what the promisc callback sees and what the
|
||||
// normal receive callback sees.
|
||||
//
|
||||
EthernetHeader2 header;
|
||||
packet->RemoveHeader(header);
|
||||
|
||||
uint16_t protocol;
|
||||
protocol = header.GetEthertype();
|
||||
|
||||
//
|
||||
// Classify the packet based on its destination.
|
||||
//
|
||||
PacketType packetType;
|
||||
|
||||
if (header.GetDest() == m_address)
|
||||
{
|
||||
packetType = PACKET_HOST;
|
||||
}
|
||||
else if (header.GetDest().IsGroup())
|
||||
{
|
||||
packetType = PACKET_MULTICAST;
|
||||
}
|
||||
else if (header.GetDest().IsBroadcast())
|
||||
{
|
||||
packetType = PACKET_BROADCAST;
|
||||
}
|
||||
else
|
||||
{
|
||||
packetType = PACKET_OTHERHOST;
|
||||
}
|
||||
|
||||
if (!m_promiscCallback.IsNull())
|
||||
{
|
||||
m_macPromiscRxTrace(originalPacket->Copy());
|
||||
m_promiscCallback(this,
|
||||
originalPacket,
|
||||
protocol,
|
||||
header.GetSrc(),
|
||||
header.GetDest(),
|
||||
packetType);
|
||||
}
|
||||
//
|
||||
// If this packet is not destined for some other host, it must be for us
|
||||
// as either a broadcast, multicast or unicast. We need to hit the mac
|
||||
// packet received trace hook and forward the packet up the stack.
|
||||
//
|
||||
if (packetType != PACKET_OTHERHOST)
|
||||
{
|
||||
//NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << Names::FindName(m_node) << "/" << Names::FindName(this) <<" : Pkt #" << originalPacket->GetUid() <<" received by the netDevice ! " << originalPacket->ToString());
|
||||
m_macRxTrace(originalPacket);
|
||||
m_macRxAnimationTrace(originalPacket, this);
|
||||
m_rxCallback(this, packet, protocol, header.GetSrc());
|
||||
m_latencyTrace(originalPacket);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ptr<Queue<Packet>>
|
||||
EthernetNetDevice::GetQueue(uint8_t index) const
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
return m_queues[index];
|
||||
}
|
||||
|
||||
void
|
||||
EthernetNetDevice::NotifyLinkUp()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
m_linkUp = true;
|
||||
m_linkChangeCallbacks();
|
||||
}
|
||||
|
||||
void
|
||||
EthernetNetDevice::SetIfIndex(const uint32_t index)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
m_ifIndex = index;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
EthernetNetDevice::GetIfIndex() const
|
||||
{
|
||||
return m_ifIndex;
|
||||
}
|
||||
|
||||
Ptr<Channel>
|
||||
EthernetNetDevice::GetChannel() const
|
||||
{
|
||||
return m_channel;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
EthernetNetDevice::SetAddress(Address address)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << address);
|
||||
m_address = Mac48Address::ConvertFrom(address);
|
||||
}
|
||||
|
||||
Address
|
||||
EthernetNetDevice::GetAddress() const
|
||||
{
|
||||
return m_address;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
EthernetNetDevice::IsLinkUp() const
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
return m_linkUp;
|
||||
}
|
||||
|
||||
void
|
||||
EthernetNetDevice::AddLinkChangeCallback(Callback<void> callback)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
m_linkChangeCallbacks.ConnectWithoutContext(callback);
|
||||
}
|
||||
|
||||
//
|
||||
// This is a ethernet device, so every transmission is a broadcast to
|
||||
// all of the devices on the channel.
|
||||
//
|
||||
bool
|
||||
EthernetNetDevice::IsBroadcast() const
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
Address
|
||||
EthernetNetDevice::GetBroadcast() const
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
return Mac48Address("ff:ff:ff:ff:ff:ff");
|
||||
}
|
||||
|
||||
bool
|
||||
EthernetNetDevice::IsMulticast() const
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
Address
|
||||
EthernetNetDevice::GetMulticast(Ipv4Address multicastGroup) const
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
return Mac48Address("01:00:5e:00:00:00");
|
||||
}
|
||||
|
||||
Address
|
||||
EthernetNetDevice::GetMulticast(Ipv6Address addr) const
|
||||
{
|
||||
NS_LOG_FUNCTION(this << addr);
|
||||
return Mac48Address("33:33:00:00:00:00");
|
||||
}
|
||||
|
||||
bool
|
||||
EthernetNetDevice::IsPointToPoint() const
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
EthernetNetDevice::IsBridge() const
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
EthernetNetDevice::Send(Ptr<Packet> packet, const Address& dest, uint16_t ethertype)
|
||||
{
|
||||
uint16_t vid = 65535;
|
||||
uint8_t pcp = 0;
|
||||
uint8_t dei = 0;
|
||||
return SendFrom(packet, GetAddress(), dest, ethertype, vid, pcp, dei);
|
||||
}
|
||||
|
||||
bool
|
||||
EthernetNetDevice::Send(Ptr<Packet> packet, const Address& dest, uint16_t ethertype, uint16_t vid, uint8_t pcp, uint8_t dei)
|
||||
{
|
||||
return SendFrom(packet, GetAddress(), dest, ethertype, vid, pcp, dei);
|
||||
}
|
||||
|
||||
bool
|
||||
EthernetNetDevice::SendFrom(Ptr<Packet> packet,
|
||||
const Address& source,
|
||||
const Address& dest,
|
||||
uint16_t ethertype)
|
||||
{
|
||||
//Call by the switch net device with a packet with a EhternetHeader2 and EthernetTrailer
|
||||
//Or by another SendFrom function that have already have a packet with header and trailer
|
||||
// /!\ source, dest, and ethertype are not use in this function but are needed in
|
||||
// the callback define by the netDevice class
|
||||
//
|
||||
// If IsLinkUp() is false it means there is no channel to send any packet
|
||||
// over so we just hit the drop trace on the packet and return an error.
|
||||
//
|
||||
if (!IsLinkUp())
|
||||
{
|
||||
m_macTxDropTrace(packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
//Add timestamp if first emission
|
||||
TimestampTag tag(Simulator::Now());
|
||||
if (!packet->FindFirstMatchingByteTag(tag))
|
||||
{
|
||||
packet->AddByteTag(tag);
|
||||
}
|
||||
m_macTxTrace(packet);
|
||||
m_macTxAnimationTrace(packet, this);
|
||||
|
||||
Ptr<Packet> pCopy = packet->Copy();
|
||||
EthernetHeader2 header;
|
||||
pCopy->RemoveHeader(header);
|
||||
uint8_t pcp = header.GetPcp();
|
||||
|
||||
NS_ASSERT_MSG(m_queues.size() > pcp, "Not enough fifos ( 0 to "<< m_queues.size()-1 <<") to handle this pcp priority ("<< unsigned(pcp) <<") on Node " <<Names::FindName(GetNode()));
|
||||
|
||||
|
||||
m_FIFOStateSnifferTrace(m_queues, m_txMachineState==BUSY, packet);
|
||||
//
|
||||
// We should enqueue and dequeue the packet to hit the tracing hooks.
|
||||
//
|
||||
if (m_queues[pcp]->Enqueue(packet))
|
||||
{
|
||||
NS_LOG_INFO(Names::FindName(this) << " Enqueue pkt #"<<packet->GetUid() << " OK !");
|
||||
//Add the event after all the already present at this exact instant to avoid
|
||||
//the beginning of a transmission if a packet will be ready at the event just
|
||||
//after but at the same time instant.
|
||||
Simulator::Schedule(Time(0), &EthernetNetDevice::CheckForReadyPacket, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Enqueue may fail (overflow)
|
||||
m_macTxDropTrace(packet);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
EthernetNetDevice::SendFrom(Ptr<Packet> packet, const Address& source, const Address& dest, uint16_t ethertype, uint16_t vid, uint8_t pcp, uint8_t dei)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << packet << dest << ethertype);
|
||||
NS_LOG_LOGIC(Names::FindName(this) << " p=" << packet->GetUid() << ", dest=" << &dest);
|
||||
|
||||
// NS_LOG_INFO(Names::FindName(this) << " SendFrom : p=" << packet->GetUid() << ", dest=" << &dest << " at " << Simulator::Now());
|
||||
|
||||
|
||||
if (vid == 65535){
|
||||
AddHeader(packet, Mac48Address::ConvertFrom(dest), Mac48Address::ConvertFrom(source), ethertype);
|
||||
}
|
||||
else{
|
||||
AddHeader(packet, Mac48Address::ConvertFrom(dest), Mac48Address::ConvertFrom(source), ethertype, vid, pcp, dei);
|
||||
}
|
||||
|
||||
EthernetTrailer trailer;
|
||||
trailer.EnableFcs(true);
|
||||
trailer.CalcFcs(packet);
|
||||
packet->AddTrailer(trailer);
|
||||
|
||||
|
||||
return SendFrom(packet, source, dest, ethertype);
|
||||
}
|
||||
|
||||
Ptr<Node>
|
||||
EthernetNetDevice::GetNode() const
|
||||
{
|
||||
return m_node;
|
||||
}
|
||||
|
||||
void
|
||||
EthernetNetDevice::SetNode(Ptr<Node> node)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
m_node = node;
|
||||
}
|
||||
|
||||
bool
|
||||
EthernetNetDevice::NeedsArp() const
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
EthernetNetDevice::SetReceiveCallback(NetDevice::ReceiveCallback cb)
|
||||
{
|
||||
m_rxCallback = cb;
|
||||
}
|
||||
|
||||
void
|
||||
EthernetNetDevice::SetPromiscReceiveCallback(NetDevice::PromiscReceiveCallback cb)
|
||||
{
|
||||
m_promiscCallback = cb;
|
||||
}
|
||||
|
||||
bool
|
||||
EthernetNetDevice::SupportsSendFrom() const
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
Address
|
||||
EthernetNetDevice::GetRemote() const
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
NS_ASSERT(m_channel->GetNDevices() == 2);
|
||||
for (std::size_t i = 0; i < m_channel->GetNDevices(); ++i)
|
||||
{
|
||||
Ptr<NetDevice> tmp = m_channel->GetDevice(i);
|
||||
if (tmp != this)
|
||||
{
|
||||
return tmp->GetAddress();
|
||||
}
|
||||
}
|
||||
NS_ASSERT(false);
|
||||
// quiet compiler.
|
||||
return Address();
|
||||
}
|
||||
|
||||
bool
|
||||
EthernetNetDevice::SetMtu(uint16_t mtu)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << mtu);
|
||||
m_mtu = mtu;
|
||||
return true;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
EthernetNetDevice::GetMtu() const
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
return m_mtu;
|
||||
}
|
||||
|
||||
}
|
||||
464
contrib/ethernet/model/ethernet-net-device.h
Normal file
464
contrib/ethernet/model/ethernet-net-device.h
Normal file
@@ -0,0 +1,464 @@
|
||||
#ifndef ETHERNET_NET_DEVICE_H
|
||||
#define ETHERNET_NET_DEVICE_H
|
||||
|
||||
#include "ns3/address.h"
|
||||
#include "ns3/callback.h"
|
||||
#include "ns3/data-rate.h"
|
||||
#include "ns3/mac48-address.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/nstime.h"
|
||||
#include "ns3/packet.h"
|
||||
#include "ns3/ptr.h"
|
||||
#include "ns3/queue-fwd.h"
|
||||
#include "ns3/traced-callback.h"
|
||||
|
||||
#include "ns3/net-device.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
class EthernetChannel;
|
||||
class ErrorModel;
|
||||
|
||||
/**
|
||||
* \ingroup ethernet
|
||||
* \class EthernetNetDevice
|
||||
* \brief A Device for a Ethernet full duplex Link.
|
||||
*
|
||||
* This EthernetNetDevice class specializes the NetDevice abstract
|
||||
* base class. Together with a EthernetChannel (and a peer
|
||||
* EthernetNetDevice), the class models, with some level of
|
||||
* abstraction, a full duplex ethernet link.
|
||||
* Key parameters or objects that can be specified for this device
|
||||
* include a queue, data rate, and interframe transmission gap (the
|
||||
* propagation delay is set in the EthernetChannel).
|
||||
*/
|
||||
|
||||
class EthernetNetDevice : public NetDevice
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \brief Get the TypeId
|
||||
*
|
||||
* \return The TypeId for this class
|
||||
*/
|
||||
static TypeId GetTypeId();
|
||||
|
||||
/**
|
||||
* Construct a EthernetNetDevice
|
||||
*
|
||||
* This is the constructor for the EthernetNetDevice. It takes as a
|
||||
* parameter a pointer to the Node to which this device is connected,
|
||||
* as well as an optional DataRate object.
|
||||
*/
|
||||
EthernetNetDevice();
|
||||
|
||||
/**
|
||||
* Destroy a EthernetNetDevice
|
||||
*
|
||||
* This is the destructor for the EthernetNetDevice.
|
||||
*/
|
||||
~EthernetNetDevice() override;
|
||||
|
||||
// Delete copy constructor and assignment operator to avoid misuse
|
||||
EthernetNetDevice& operator=(const EthernetNetDevice&) = delete;
|
||||
EthernetNetDevice(const EthernetNetDevice&) = delete;
|
||||
|
||||
/**
|
||||
* Set the Data Rate used for transmission of packets. The data rate is
|
||||
* set in the Attach () method from the corresponding field in the channel
|
||||
* to which the device is attached. It can be overridden using this method.
|
||||
*
|
||||
* \param bps the data rate at which this object operates
|
||||
*/
|
||||
void SetDataRate(DataRate bps);
|
||||
|
||||
/**
|
||||
* Attach the device to a channel.
|
||||
*
|
||||
* \param ch Ptr to the channel to which this object is being attached.
|
||||
* \return true if the operation was successful (always true actually)
|
||||
*/
|
||||
bool Attach(Ptr<EthernetChannel> ch);
|
||||
|
||||
/**
|
||||
* Attach a queue to the EthernetNetDevice.
|
||||
*
|
||||
* The EthernetNetDevice "owns" a queue that implements a queueing
|
||||
* method such as DropTailQueue or RedQueue
|
||||
*
|
||||
* \param queue Ptr to the new queue.
|
||||
*/
|
||||
void SetQueue(Ptr<Queue<Packet>> queue);
|
||||
|
||||
/**
|
||||
* Get a copy of the attached Queue.
|
||||
*
|
||||
* \param index Queue index
|
||||
* \returns Ptr to the queue.
|
||||
*/
|
||||
Ptr<Queue<Packet>> GetQueue(uint8_t index) const;
|
||||
|
||||
/**
|
||||
* Attach a receive ErrorModel to the EthernetNetDevice.
|
||||
*
|
||||
* The EthernetNetDevice may optionally include an ErrorModel in
|
||||
* the packet receive chain.
|
||||
*
|
||||
* \param em Ptr to the ErrorModel.
|
||||
*/
|
||||
void SetReceiveErrorModel(Ptr<ErrorModel> em);
|
||||
|
||||
/**
|
||||
* Receive a packet from a connected EthernetNetDevice.
|
||||
*
|
||||
* The EthernetNetDevice receives packets from its connected channel
|
||||
* and forwards them up the protocol stack. This is the public method
|
||||
* used by the channel to indicate that the last bit of a packet has
|
||||
* arrived at the device.
|
||||
*
|
||||
* \param p Ptr to the received packet.
|
||||
*/
|
||||
virtual void Receive(Ptr<Packet> p);
|
||||
|
||||
// The remaining methods are documented in ns3::NetDevice*
|
||||
|
||||
void SetIfIndex(const uint32_t index) override;
|
||||
uint32_t GetIfIndex() const override;
|
||||
|
||||
Ptr<Channel> GetChannel() const override;
|
||||
|
||||
void SetAddress(Address address) override;
|
||||
Address GetAddress() const override;
|
||||
|
||||
bool SetMtu(const uint16_t mtu) override;
|
||||
uint16_t GetMtu() const override;
|
||||
|
||||
bool IsLinkUp() const override;
|
||||
|
||||
void AddLinkChangeCallback(Callback<void> callback) override;
|
||||
|
||||
bool IsBroadcast() const override;
|
||||
Address GetBroadcast() const override;
|
||||
|
||||
bool IsMulticast() const override;
|
||||
Address GetMulticast(Ipv4Address multicastGroup) const override;
|
||||
|
||||
bool IsPointToPoint() const override;
|
||||
bool IsBridge() const override;
|
||||
|
||||
bool Send(Ptr<Packet> packet, const Address& dest, uint16_t ethertype) override;
|
||||
bool Send(Ptr<Packet> packet, const Address& dest, uint16_t ethertype, uint16_t vid, uint8_t pcp, uint8_t dei);
|
||||
virtual bool SendFrom(Ptr<Packet> packet,
|
||||
const Address& source,
|
||||
const Address& dest,
|
||||
uint16_t ethertype) override;
|
||||
bool SendFrom(Ptr<Packet> packet,
|
||||
const Address& source,
|
||||
const Address& dest,
|
||||
uint16_t ethertype,
|
||||
uint16_t vid,
|
||||
uint8_t pcp,
|
||||
uint8_t dei);
|
||||
|
||||
Ptr<Node> GetNode() const override;
|
||||
void SetNode(Ptr<Node> node) override;
|
||||
|
||||
bool NeedsArp() const override;
|
||||
|
||||
void SetReceiveCallback(NetDevice::ReceiveCallback cb) override;
|
||||
|
||||
Address GetMulticast(Ipv6Address addr) const override;
|
||||
|
||||
void SetPromiscReceiveCallback(PromiscReceiveCallback cb) override;
|
||||
bool SupportsSendFrom() const override;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* \brief Dispose of the object
|
||||
*/
|
||||
void DoDispose() override;
|
||||
|
||||
/**
|
||||
* \returns the address of the remote device connected to this device
|
||||
* through the ethernet channel.
|
||||
*/
|
||||
Address GetRemote() const;
|
||||
|
||||
/**
|
||||
* Adds the necessary headers and trailers to a packet of data in order to
|
||||
* respect the protocol implemented by the agent.
|
||||
* \param p packet
|
||||
* \param dst Dst mac address
|
||||
* \param src Src mac address
|
||||
* \param ethertype ethertype
|
||||
*/
|
||||
void AddHeader(Ptr<Packet> p, Mac48Address dst, Mac48Address src, uint16_t ethertype);
|
||||
|
||||
/**
|
||||
* Adds the necessary headers to a packet of data in order to
|
||||
* respect the protocol implemented by the agent.
|
||||
* \param p packet
|
||||
* \param dst Dst mac address
|
||||
* \param src Src mac address
|
||||
* \param ethertype ethertype
|
||||
* \param vid vlain id
|
||||
* \param pcp pcp field
|
||||
* \param dei dei bit
|
||||
*/
|
||||
void AddHeader(Ptr<Packet> p, Mac48Address dst, Mac48Address src, uint16_t ethertype, uint16_t vid, uint8_t pcp, uint8_t dei);
|
||||
|
||||
/**
|
||||
* Start Sending a Packet Down the Wire.
|
||||
*
|
||||
* The TransmitStart method is the method that is used internally in the
|
||||
* EthernetNetDevice to begin the process of sending a packet out on
|
||||
* the channel. The corresponding method is called on the channel to let
|
||||
* it know that the physical device this class represents has virtually
|
||||
* started sending signals. An event is scheduled for the time at which
|
||||
* the bits have been completely transmitted.
|
||||
*
|
||||
* \see EthernetChannel::TransmitStart ()
|
||||
* \see TransmitComplete()
|
||||
* \param p a reference to the packet to send
|
||||
* \returns true if success, false on failure
|
||||
*/
|
||||
bool TransmitStart(Ptr<Packet> p);
|
||||
|
||||
/**
|
||||
* Stop Sending a Packet Down the Wire and Begin the Interframe Gap.
|
||||
*
|
||||
* The TransmitComplete method is used internally to finish the process
|
||||
* of sending a packet out on the channel.
|
||||
*/
|
||||
void TransmitComplete();
|
||||
|
||||
/**
|
||||
* Find the nextEligible Queue for transimission
|
||||
*
|
||||
* \returns Int id to the queue.
|
||||
*/
|
||||
virtual int TransmitSelection();
|
||||
|
||||
virtual void CheckForReadyPacket();
|
||||
|
||||
|
||||
/**
|
||||
* \brief Make the link up and running
|
||||
*
|
||||
* It calls also the linkChange callback.
|
||||
*/
|
||||
void NotifyLinkUp();
|
||||
|
||||
/**
|
||||
* Enumeration of the states of the transmit machine of the net device.
|
||||
*/
|
||||
enum TxMachineState
|
||||
{
|
||||
READY, /**< The transmitter is ready to begin transmission of a packet */
|
||||
BUSY /**< The transmitter is busy transmitting a packet */
|
||||
};
|
||||
|
||||
/**
|
||||
* The state of the Net Device transmit state machine.
|
||||
*/
|
||||
TxMachineState m_txMachineState;
|
||||
|
||||
/**
|
||||
* The data rate that the Net Device uses to simulate packet transmission
|
||||
* timing.
|
||||
*/
|
||||
DataRate m_bps;
|
||||
|
||||
/**
|
||||
* The preamble and start of frame delimiter gap that the Net Device uses to throttle packet
|
||||
* transmission in bytes
|
||||
*/
|
||||
uint8_t m_preambleAndSFDGap;
|
||||
|
||||
/**
|
||||
* The interframe gap that the Net Device uses to throttle packet
|
||||
* transmission in bytes
|
||||
*/
|
||||
uint8_t m_interframeGap;
|
||||
|
||||
/**
|
||||
* The EthernetChannel to which this EthernetNetDevice has been
|
||||
* attached.
|
||||
*/
|
||||
Ptr<EthernetChannel> m_channel;
|
||||
|
||||
/**
|
||||
* The Queues which this EthernetNetDevice uses as a packet source.
|
||||
* Management of this Queues has been delegated to the EthernetNetDevice
|
||||
* and it has the responsibility for deletion.
|
||||
* \see class DropTailQueue
|
||||
*/
|
||||
std::vector<Ptr<Queue<Packet>>> m_queues;
|
||||
|
||||
/**
|
||||
* Error model for receive packet events
|
||||
*/
|
||||
Ptr<ErrorModel> m_receiveErrorModel;
|
||||
|
||||
/**
|
||||
* The trace source fired when packets come into the "top" of the device
|
||||
* at the L3/L2 transition, before being queued for transmission.
|
||||
*/
|
||||
TracedCallback<Ptr<const Packet>> m_macTxTrace;
|
||||
|
||||
/**
|
||||
* The trace source fired when packets coming into the "top" of the device
|
||||
* at the L3/L2 transition are dropped before being queued for transmission.
|
||||
*/
|
||||
TracedCallback<Ptr<const Packet>> m_macTxDropTrace;
|
||||
|
||||
/**
|
||||
* The trace source fired for packets successfully received by the device
|
||||
* immediately before being forwarded up to higher layers (at the L2/L3
|
||||
* transition). This is a promiscuous trace (which doesn't mean a lot here
|
||||
* in the point-to-point device).
|
||||
*/
|
||||
TracedCallback<Ptr<const Packet>> m_macPromiscRxTrace;
|
||||
|
||||
/**
|
||||
* The trace source fired for packets successfully received by the device
|
||||
* immediately before being forwarded up to higher layers (at the L2/L3
|
||||
* transition). This is a non-promiscuous trace (which doesn't mean a lot
|
||||
* here in the point-to-point device).
|
||||
*/
|
||||
TracedCallback<Ptr<const Packet>> m_macRxTrace;
|
||||
|
||||
/**
|
||||
* The trace source fired for packets successfully received by the device
|
||||
* but are dropped before being forwarded up to higher layers (at the L2/L3
|
||||
* transition).
|
||||
*/
|
||||
TracedCallback<Ptr<const Packet>> m_macRxDropTrace;
|
||||
|
||||
/**
|
||||
* The trace source fired when a packet begins the transmission process on
|
||||
* the medium.
|
||||
*/
|
||||
TracedCallback<Ptr<const Packet>> m_phyTxBeginTrace;
|
||||
|
||||
/**
|
||||
* The trace source fired when a packet ends the transmission process on
|
||||
* the medium.
|
||||
*/
|
||||
TracedCallback<Ptr<const Packet>> m_phyTxEndTrace;
|
||||
|
||||
/**
|
||||
* The trace source fired when the phy layer drops a packet before it tries
|
||||
* to transmit it.
|
||||
*/
|
||||
TracedCallback<Ptr<const Packet>> m_phyTxDropTrace;
|
||||
|
||||
/**
|
||||
* The trace source fired when a packet begins the reception process from
|
||||
* the medium -- when the simulated first bit(s) arrive.
|
||||
*/
|
||||
TracedCallback<Ptr<const Packet>> m_phyRxBeginTrace;
|
||||
|
||||
/**
|
||||
* The trace source fired when a packet ends the reception process from
|
||||
* the medium.
|
||||
*/
|
||||
TracedCallback<Ptr<const Packet>> m_phyRxEndTrace;
|
||||
|
||||
/**
|
||||
* The trace source fired when the phy layer drops a packet it has received.
|
||||
* This happens if the receiver is not enabled or the error model is active
|
||||
* and indicates that the packet is corrupt.
|
||||
*/
|
||||
TracedCallback<Ptr<const Packet>> m_phyRxDropTrace;
|
||||
|
||||
/**
|
||||
* The trace source fired when the packet is receive to compute latency.
|
||||
*/
|
||||
TracedCallback<Ptr<const Packet>> m_latencyTrace;
|
||||
|
||||
/**
|
||||
* TracedCallback signature for packet transmission/reception events
|
||||
* (for external visualyzer).
|
||||
*
|
||||
* \param [in] packet The packet being transmitted.
|
||||
* \param [in] tx or rx NetDevice.
|
||||
*/
|
||||
typedef void (*MacTxAnimationCallback)(Ptr<const Packet> packet,
|
||||
Ptr<NetDevice> device);
|
||||
|
||||
TracedCallback<Ptr<const Packet>, Ptr<NetDevice>> m_macTxAnimationTrace;
|
||||
TracedCallback<Ptr<const Packet>, Ptr<NetDevice>> m_macRxAnimationTrace;
|
||||
/**
|
||||
* A trace source that emulates a non-promiscuous protocol sniffer connected
|
||||
* to the device. Unlike your average everyday sniffer, this trace source
|
||||
* will not fire on PACKET_OTHERHOST events.
|
||||
*
|
||||
* On the transmit size, this trace hook will fire after a packet is dequeued
|
||||
* from the device queue for transmission. In Linux, for example, this would
|
||||
* correspond to the point just before a device \c hard_start_xmit where
|
||||
* \c dev_queue_xmit_nit is called to dispatch the packet to the PF_PACKET
|
||||
* ETH_P_ALL handlers.
|
||||
*
|
||||
* On the receive side, this trace hook will fire when a packet is received,
|
||||
* just before the receive callback is executed. In Linux, for example,
|
||||
* this would correspond to the point at which the packet is dispatched to
|
||||
* packet sniffers in \c netif_receive_skb.
|
||||
*/
|
||||
TracedCallback<Ptr<const Packet>> m_snifferTrace;
|
||||
|
||||
/**
|
||||
* A trace source that emulates a promiscuous mode protocol sniffer connected
|
||||
* to the device. This trace source fire on packets destined for any host
|
||||
* just like your average everyday packet sniffer.
|
||||
*
|
||||
* On the transmit size, this trace hook will fire after a packet is dequeued
|
||||
* from the device queue for transmission. In Linux, for example, this would
|
||||
* correspond to the point just before a device \c hard_start_xmit where
|
||||
* \c dev_queue_xmit_nit is called to dispatch the packet to the PF_PACKET
|
||||
* ETH_P_ALL handlers.
|
||||
*
|
||||
* On the receive side, this trace hook will fire when a packet is received,
|
||||
* just before the receive callback is executed. In Linux, for example,
|
||||
* this would correspond to the point at which the packet is dispatched to
|
||||
* packet sniffers in \c netif_receive_skb.
|
||||
*/
|
||||
TracedCallback<Ptr<const Packet>> m_promiscSnifferTrace;
|
||||
|
||||
|
||||
TracedCallback<std::vector<Ptr<Queue<Packet>>>,
|
||||
bool,
|
||||
Ptr<const Packet>> m_FIFOStateSnifferTrace;
|
||||
|
||||
|
||||
Ptr<Node> m_node; //!< Node owning this NetDevice
|
||||
Mac48Address m_address; //!< Mac48Address of this NetDevice
|
||||
NetDevice::ReceiveCallback m_rxCallback; //!< Receive callback
|
||||
NetDevice::PromiscReceiveCallback m_promiscCallback; //!< Receive callback
|
||||
// (promisc data)
|
||||
uint32_t m_ifIndex; //!< Index of the interface
|
||||
bool m_linkUp; //!< Identify if the link is up or not
|
||||
TracedCallback<> m_linkChangeCallbacks; //!< Callback for the link change event
|
||||
|
||||
static const uint16_t DEFAULT_MTU = 1500; //!< Default MTU
|
||||
|
||||
/**
|
||||
* \brief The Maximum Transmission Unit
|
||||
*
|
||||
* This corresponds to the maximum
|
||||
* number of bytes that can be transmitted as seen from higher layers.
|
||||
* This corresponds to the 1500 byte MTU size often seen on IP over
|
||||
* Ethernet.
|
||||
*/
|
||||
uint32_t m_mtu;
|
||||
|
||||
Ptr<Packet> m_currentPkt; //!< Current packet processed
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* ETHERNET_NET_DEVICE_H */
|
||||
77
contrib/ethernet/model/switch-channel.cc
Normal file
77
contrib/ethernet/model/switch-channel.cc
Normal file
@@ -0,0 +1,77 @@
|
||||
#include "switch-channel.h"
|
||||
|
||||
#include "ns3/log.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
* \ingroup ethernet
|
||||
* ns3::SwitchChannel implementation.
|
||||
*/
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("SwitchChannel");
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED(SwitchChannel);
|
||||
|
||||
TypeId
|
||||
SwitchChannel::GetTypeId()
|
||||
{
|
||||
static TypeId tid = TypeId("ns3::SwitchChannel")
|
||||
.SetParent<Channel>()
|
||||
.SetGroupName("Ethernet")
|
||||
.AddConstructor<SwitchChannel>();
|
||||
return tid;
|
||||
}
|
||||
|
||||
SwitchChannel::SwitchChannel()
|
||||
: Channel()
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
}
|
||||
|
||||
SwitchChannel::~SwitchChannel()
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
|
||||
for (auto iter = m_switchedChannels.begin(); iter != m_switchedChannels.end(); iter++)
|
||||
{
|
||||
*iter = nullptr;
|
||||
}
|
||||
m_switchedChannels.clear();
|
||||
}
|
||||
|
||||
void
|
||||
SwitchChannel::AddChannel(Ptr<Channel> switchedChannel)
|
||||
{
|
||||
m_switchedChannels.push_back(switchedChannel);
|
||||
}
|
||||
|
||||
std::size_t
|
||||
SwitchChannel::GetNDevices() const
|
||||
{
|
||||
uint32_t ndevices = 0;
|
||||
for (auto iter = m_switchedChannels.begin(); iter != m_switchedChannels.end(); iter++)
|
||||
{
|
||||
ndevices += (*iter)->GetNDevices();
|
||||
}
|
||||
return ndevices;
|
||||
}
|
||||
|
||||
Ptr<NetDevice>
|
||||
SwitchChannel::GetDevice(std::size_t i) const
|
||||
{
|
||||
std::size_t ndevices = 0;
|
||||
for (auto iter = m_switchedChannels.begin(); iter != m_switchedChannels.end(); iter++)
|
||||
{
|
||||
if ((i - ndevices) < (*iter)->GetNDevices())
|
||||
{
|
||||
return (*iter)->GetDevice(i - ndevices);
|
||||
}
|
||||
ndevices += (*iter)->GetNDevices();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
59
contrib/ethernet/model/switch-channel.h
Normal file
59
contrib/ethernet/model/switch-channel.h
Normal file
@@ -0,0 +1,59 @@
|
||||
#ifndef SWITCH_CHANNEL_H
|
||||
#define SWITCH_CHANNEL_H
|
||||
|
||||
#include "ns3/channel.h"
|
||||
#include "ns3/net-device.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* \file
|
||||
* \ingroup ethernet
|
||||
* ns3::SwitchChannel declaration.
|
||||
*/
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
/**
|
||||
* \ingroup bridge
|
||||
*
|
||||
* \brief Virtual channel implementation for bridges (BridgeNetDevice).
|
||||
*
|
||||
* Just like SwitchNetDevice aggregates multiple NetDevices,
|
||||
* SwitchChannel aggregates multiple channels and make them appear as
|
||||
* a single channel to upper layers.
|
||||
* This class is greatly inspire form BridgeChannel
|
||||
*/
|
||||
class SwitchChannel : public Channel
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \brief Get the type ID.
|
||||
* \return the object TypeId
|
||||
*/
|
||||
static TypeId GetTypeId();
|
||||
SwitchChannel();
|
||||
~SwitchChannel() override;
|
||||
|
||||
// Delete copy constructor and assignment operator to avoid misuse
|
||||
SwitchChannel(const SwitchChannel&) = delete;
|
||||
SwitchChannel& operator=(const SwitchChannel&) = delete;
|
||||
|
||||
/**
|
||||
* Adds a channel to the bridged pool
|
||||
* \param bridgedChannel the channel to add to the pool
|
||||
*/
|
||||
void AddChannel(Ptr<Channel> bridgedChannel);
|
||||
|
||||
// virtual methods implementation, from Channel
|
||||
std::size_t GetNDevices() const override;
|
||||
Ptr<NetDevice> GetDevice(std::size_t i) const override;
|
||||
|
||||
private:
|
||||
std::vector<Ptr<Channel>> m_switchedChannels; //!< pool of switched channels
|
||||
};
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif /* SWITCH_CHANNEL_H */
|
||||
427
contrib/ethernet/model/switch-net-device.cc
Normal file
427
contrib/ethernet/model/switch-net-device.cc
Normal file
@@ -0,0 +1,427 @@
|
||||
#include "switch-net-device.h"
|
||||
|
||||
#include "ns3/boolean.h"
|
||||
#include "ns3/channel.h"
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/packet.h"
|
||||
#include "ns3/uinteger.h"
|
||||
#include "ns3/names.h"
|
||||
#include "ns3/random-variable-stream.h"
|
||||
|
||||
#include "ns3/ethernet-header2.h"
|
||||
#include "ns3/net-device.h"
|
||||
|
||||
|
||||
/**
|
||||
* \file
|
||||
* \ingroup ethernet
|
||||
* ns3::SwitchNetDevice implementation.
|
||||
*/
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("SwitchNetDevice");
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED(SwitchNetDevice);
|
||||
|
||||
TypeId
|
||||
SwitchNetDevice::GetTypeId()
|
||||
{
|
||||
static TypeId tid =
|
||||
TypeId("ns3::SwitchNetDevice")
|
||||
.SetParent<NetDevice>()
|
||||
.SetGroupName("Ethernet")
|
||||
.AddConstructor<SwitchNetDevice>()
|
||||
.AddAttribute("Mtu",
|
||||
"The MAC-level Maximum Transmission Unit",
|
||||
UintegerValue(1500),
|
||||
MakeUintegerAccessor(&SwitchNetDevice::SetMtu, &SwitchNetDevice::GetMtu),
|
||||
MakeUintegerChecker<uint16_t>())
|
||||
.AddAttribute("MinForwardingLatency",
|
||||
"The minimum latency experienced by the packet during forwarding",
|
||||
TimeValue(Seconds(0)),
|
||||
MakeTimeAccessor(&SwitchNetDevice::m_minForwardingLatency),
|
||||
MakeTimeChecker())
|
||||
.AddAttribute("MaxForwardingLatency",
|
||||
"The maximun latency experienced by the packet during forwarding",
|
||||
TimeValue(Seconds(0)),
|
||||
MakeTimeAccessor(&SwitchNetDevice::m_maxForwardingLatency),
|
||||
MakeTimeChecker())
|
||||
.AddAttribute("MaxPortNumber",
|
||||
"The maximum number of port",
|
||||
UintegerValue(65535),
|
||||
MakeUintegerAccessor(&SwitchNetDevice::m_maxPortNumber),
|
||||
MakeUintegerChecker<uint16_t>())
|
||||
.AddAttribute("MaxFdbEntryNumber",
|
||||
"The maximum number of entry in the forwarding database",
|
||||
UintegerValue(65535),
|
||||
MakeUintegerAccessor(&SwitchNetDevice::m_maxFdbEntryNumber),
|
||||
MakeUintegerChecker<uint16_t>());
|
||||
return tid;
|
||||
}
|
||||
|
||||
SwitchNetDevice::SwitchNetDevice()
|
||||
: m_node(nullptr),
|
||||
m_ifIndex(0)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
m_channel = CreateObject<SwitchChannel>();
|
||||
}
|
||||
|
||||
SwitchNetDevice::~SwitchNetDevice()
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
}
|
||||
|
||||
void
|
||||
SwitchNetDevice::DoDispose()
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
for (auto iter = m_ports.begin(); iter != m_ports.end(); iter++)
|
||||
{
|
||||
*iter = nullptr;
|
||||
}
|
||||
m_ports.clear();
|
||||
m_forwardingTable.clear();
|
||||
m_channel = nullptr;
|
||||
m_node = nullptr;
|
||||
NetDevice::DoDispose();
|
||||
}
|
||||
|
||||
void
|
||||
SwitchNetDevice::ReceiveFromDevice(Ptr<NetDevice> incomingPort,
|
||||
Ptr<const Packet> packet,
|
||||
uint16_t protocol,
|
||||
const Address& src,
|
||||
const Address& dst,
|
||||
PacketType packetType)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
NS_LOG_DEBUG("UID is " << packet->GetUid());
|
||||
|
||||
Mac48Address src48 = Mac48Address::ConvertFrom(src);
|
||||
Mac48Address dst48 = Mac48Address::ConvertFrom(dst);
|
||||
|
||||
if (!m_promiscRxCallback.IsNull())
|
||||
{
|
||||
m_promiscRxCallback(this, packet, protocol, src, dst, packetType);
|
||||
}
|
||||
switch (packetType)
|
||||
{
|
||||
case PACKET_HOST:
|
||||
if (dst48 == m_address)
|
||||
{
|
||||
m_rxCallback(this, packet, protocol, src);
|
||||
}
|
||||
break;
|
||||
case PACKET_MULTICAST:
|
||||
case PACKET_BROADCAST:
|
||||
m_rxCallback(this, packet, protocol, src);
|
||||
ForwardBroadcast(incomingPort, packet, protocol, src48, dst48);
|
||||
break;
|
||||
|
||||
case PACKET_OTHERHOST:
|
||||
if (dst48 == m_address)
|
||||
{
|
||||
m_rxCallback(this, packet, protocol, src);
|
||||
}
|
||||
else
|
||||
{
|
||||
Forward(incomingPort, packet, protocol, src48, dst48);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SwitchNetDevice::Forward(Ptr<NetDevice> incomingPort,
|
||||
Ptr<const Packet> packet,
|
||||
uint16_t protocol,
|
||||
Mac48Address src,
|
||||
Mac48Address dst)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
Ptr<Packet> originalPacket = packet->Copy();
|
||||
EthernetHeader2 header;
|
||||
originalPacket->RemoveHeader(header);
|
||||
uint16_t vid = header.GetVid();
|
||||
//NS_LOG_INFO(Names::FindName(this) << " Look in forwarding table for Pkt #" << packet->GetUid());
|
||||
std::vector<Ptr<NetDevice>> outPorts = GetOutputPortsFromForwardingTable(dst, vid);
|
||||
EventId e;
|
||||
int s = outPorts.size();
|
||||
for(int i=0; i < s; i++){
|
||||
//Avoid sending on the incomingPort
|
||||
if(outPorts[i] != incomingPort){
|
||||
Ptr<UniformRandomVariable> randVar = CreateObject<UniformRandomVariable>();
|
||||
Time forwardingLatency = NanoSeconds(randVar->GetValue(m_minForwardingLatency.GetNanoSeconds(), m_maxForwardingLatency.GetNanoSeconds()));
|
||||
Simulator::Schedule(forwardingLatency, &NetDevice::SendFrom, outPorts[i], packet->Copy(), src, dst, protocol);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SwitchNetDevice::ForwardBroadcast(Ptr<NetDevice> incomingPort,
|
||||
Ptr<const Packet> packet,
|
||||
uint16_t protocol,
|
||||
Mac48Address src,
|
||||
Mac48Address dst)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
|
||||
Forward(incomingPort, packet, protocol, src, dst);
|
||||
}
|
||||
|
||||
std::vector<Ptr<NetDevice>>
|
||||
SwitchNetDevice::GetOutputPortsFromForwardingTable(Mac48Address dest, uint16_t vid)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
int s = m_forwardingTable.size();
|
||||
for(int i=0; i < s; i++){
|
||||
if(m_forwardingTable[i].dest == dest and m_forwardingTable[i].vid==vid){
|
||||
// NS_LOG_INFO(Names::FindName(this) << " Forwarding Table : Match on vid "<< vid << " for " << m_forwardingTable[i].associatedPorts.size() << " output port(s) ");
|
||||
return m_forwardingTable[i].associatedPorts;
|
||||
}
|
||||
}
|
||||
// NS_LOG_INFO(Names::FindName(this) << " Forwarding Table : No Match on vid "<< vid);
|
||||
return {};
|
||||
}
|
||||
|
||||
void
|
||||
SwitchNetDevice::AddForwardingTableEntry(Mac48Address dest, uint16_t vid, std::vector<Ptr<NetDevice>> outPorts)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
NS_ASSERT_MSG(m_forwardingTable.size() < m_maxFdbEntryNumber, "Trying to add more forwarding database entry than the " << m_maxFdbEntryNumber << " available.");
|
||||
PortsToVidAssociation entry = {dest, vid, outPorts};
|
||||
m_forwardingTable.insert(m_forwardingTable.end(), entry);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
SwitchNetDevice::GetNSwitchPorts() const
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
return m_ports.size();
|
||||
}
|
||||
|
||||
Ptr<NetDevice>
|
||||
SwitchNetDevice::GetSwitchPort(uint32_t n) const
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
return m_ports[n];
|
||||
}
|
||||
|
||||
void
|
||||
SwitchNetDevice::AddSwitchPort(Ptr<NetDevice> switchPort)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
NS_ASSERT_MSG(m_ports.size() < m_maxPortNumber, "Trying to add more switch port than the " << m_maxPortNumber << " available.");
|
||||
//NS_ASSERT(switchPort != this);
|
||||
if (!Mac48Address::IsMatchingType(switchPort->GetAddress()))
|
||||
{
|
||||
NS_FATAL_ERROR("Device does not support eui 48 addresses: cannot be added to switch.");
|
||||
}
|
||||
if (!switchPort->SupportsSendFrom())
|
||||
{
|
||||
NS_FATAL_ERROR("Device does not support SendFrom: cannot be added to switch.");
|
||||
}
|
||||
if (m_address == Mac48Address())
|
||||
{
|
||||
m_address = Mac48Address::ConvertFrom(switchPort->GetAddress());
|
||||
}
|
||||
|
||||
NS_LOG_DEBUG("RegisterProtocolHandler for " << switchPort->GetInstanceTypeId().GetName());
|
||||
m_node->RegisterProtocolHandler(MakeCallback(&SwitchNetDevice::ReceiveFromDevice, this),
|
||||
0,
|
||||
switchPort,
|
||||
true);
|
||||
m_ports.push_back(switchPort);
|
||||
m_channel->AddChannel(switchPort->GetChannel());
|
||||
}
|
||||
|
||||
void
|
||||
SwitchNetDevice::SetIfIndex(const uint32_t index)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
m_ifIndex = index;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
SwitchNetDevice::GetIfIndex() const
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
return m_ifIndex;
|
||||
}
|
||||
|
||||
Ptr<Channel>
|
||||
SwitchNetDevice::GetChannel() const
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
return m_channel;
|
||||
}
|
||||
|
||||
void
|
||||
SwitchNetDevice::SetAddress(Address address)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
m_address = Mac48Address::ConvertFrom(address);
|
||||
}
|
||||
|
||||
Address
|
||||
SwitchNetDevice::GetAddress() const
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
return m_address;
|
||||
}
|
||||
|
||||
bool
|
||||
SwitchNetDevice::SetMtu(const uint16_t mtu)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
m_mtu = mtu;
|
||||
return true;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
SwitchNetDevice::GetMtu() const
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
return m_mtu;
|
||||
}
|
||||
|
||||
bool
|
||||
SwitchNetDevice::IsLinkUp() const
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
SwitchNetDevice::AddLinkChangeCallback(Callback<void> callback)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
SwitchNetDevice::IsBroadcast() const
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
return true;
|
||||
}
|
||||
|
||||
Address
|
||||
SwitchNetDevice::GetBroadcast() const
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
return Mac48Address("ff:ff:ff:ff:ff:ff");
|
||||
}
|
||||
|
||||
bool
|
||||
SwitchNetDevice::IsMulticast() const
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
return true;
|
||||
}
|
||||
|
||||
Address
|
||||
SwitchNetDevice::GetMulticast(Ipv4Address multicastGroup) const
|
||||
{
|
||||
NS_LOG_FUNCTION(this << multicastGroup);
|
||||
Mac48Address multicast = Mac48Address::GetMulticast(multicastGroup);
|
||||
return multicast;
|
||||
}
|
||||
|
||||
bool
|
||||
SwitchNetDevice::IsPointToPoint() const
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
SwitchNetDevice::IsBridge() const
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
SwitchNetDevice::Send(Ptr<Packet> packet, const Address& dest, uint16_t protocolNumber)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
return SendFrom(packet, m_address, dest, protocolNumber);
|
||||
}
|
||||
|
||||
bool
|
||||
SwitchNetDevice::SendFrom(Ptr<Packet> packet,
|
||||
const Address& source,
|
||||
const Address& dest,
|
||||
uint16_t protocolNumber)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
Mac48Address src = Mac48Address::ConvertFrom(source);
|
||||
Mac48Address dst = Mac48Address::ConvertFrom(dest);
|
||||
|
||||
|
||||
Ptr<Packet> originalPacket = packet->Copy();
|
||||
EthernetHeader2 header;
|
||||
originalPacket->RemoveHeader(header);
|
||||
uint16_t vid = header.GetVid();
|
||||
|
||||
std::vector<Ptr<NetDevice>> outPorts = GetOutputPortsFromForwardingTable(dst, vid);
|
||||
int s = outPorts.size();
|
||||
for(int i=0; i < s; i++){
|
||||
outPorts[i]->SendFrom(packet->Copy(), src, dst, protocolNumber);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Ptr<Node>
|
||||
SwitchNetDevice::GetNode() const
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
return m_node;
|
||||
}
|
||||
|
||||
void
|
||||
SwitchNetDevice::SetNode(Ptr<Node> node)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
m_node = node;
|
||||
}
|
||||
|
||||
bool
|
||||
SwitchNetDevice::NeedsArp() const
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
SwitchNetDevice::SetReceiveCallback(NetDevice::ReceiveCallback cb)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
m_rxCallback = cb;
|
||||
}
|
||||
|
||||
void
|
||||
SwitchNetDevice::SetPromiscReceiveCallback(NetDevice::PromiscReceiveCallback cb)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
m_promiscRxCallback = cb;
|
||||
}
|
||||
|
||||
bool
|
||||
SwitchNetDevice::SupportsSendFrom() const
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS();
|
||||
return true;
|
||||
}
|
||||
|
||||
Address
|
||||
SwitchNetDevice::GetMulticast(Ipv6Address addr) const
|
||||
{
|
||||
NS_LOG_FUNCTION(this << addr);
|
||||
return Mac48Address::GetMulticast(addr);
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
220
contrib/ethernet/model/switch-net-device.h
Normal file
220
contrib/ethernet/model/switch-net-device.h
Normal file
@@ -0,0 +1,220 @@
|
||||
#ifndef SWITCH_NET_DEVICE_H
|
||||
#define SWITCH_NET_DEVICE_H
|
||||
|
||||
#include "switch-channel.h"
|
||||
|
||||
#include "ns3/net-device.h"
|
||||
#include "ns3/mac48-address.h"
|
||||
#include "ns3/net-device.h"
|
||||
#include "ns3/nstime.h"
|
||||
#include "ns3/simulator.h"
|
||||
|
||||
#include <map>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
|
||||
/**
|
||||
* \file
|
||||
* \ingroup ethernet
|
||||
* ns3::SwitchNetDevice declaration.
|
||||
*/
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
class Node;
|
||||
|
||||
/**
|
||||
* \brief a virtual net device that bridges multiple LAN segments
|
||||
*
|
||||
* The SwitchNetDevice object is a "virtual" netdevice that aggregates
|
||||
* multiple "real" netdevices and implements the data plane forwarding
|
||||
* part of IEEE 802.1D. By adding a SwitchNetDevice to a Node, it
|
||||
* will act as a "switch" to multiple LAN segments.
|
||||
*
|
||||
* \attention The switch netdevice don't implement a "Learning bridge" algorithm
|
||||
* or Spanning Tree Protocol as described in 802.1D
|
||||
*
|
||||
* \attention Switching is designed to work only with Ethernet NetDevices
|
||||
* modelling IEEE 802-style technologies, such as EthernetNetDevice
|
||||
*/
|
||||
|
||||
/**
|
||||
* \ingroup ethernet
|
||||
* \brief a virtual net device that bridges multiple LAN segments
|
||||
*/
|
||||
class SwitchNetDevice : public NetDevice
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \brief Get the type ID.
|
||||
* \return the object TypeId
|
||||
*/
|
||||
static TypeId GetTypeId();
|
||||
SwitchNetDevice();
|
||||
~SwitchNetDevice() override;
|
||||
|
||||
// Delete copy constructor and assignment operator to avoid misuse
|
||||
SwitchNetDevice(const SwitchNetDevice&) = delete;
|
||||
SwitchNetDevice& operator=(const SwitchNetDevice&) = delete;
|
||||
|
||||
/**
|
||||
* \brief Add a 'port' to a switch device
|
||||
* \param switchPort the NetDevice to add
|
||||
*
|
||||
* This method adds a new switch port to a SwitchNetDevice, so that
|
||||
* the new switch port NetDevice becomes part of the switch and L2
|
||||
* frames start being forwarded to/from this NetDevice.
|
||||
*
|
||||
* \attention The netdevice that is being added as switch port must
|
||||
* _not_ have an IP address. In order to add IP connectivity to a
|
||||
* bridging node you must enable IP on the SwitchNetDevice itself,
|
||||
* never on its port netdevices.
|
||||
*/
|
||||
void AddSwitchPort(Ptr<NetDevice> switchPort);
|
||||
|
||||
/**
|
||||
* \brief Gets the number of switched 'ports', i.e., the NetDevices currently switched.
|
||||
*
|
||||
* \return the number of switched ports.
|
||||
*/
|
||||
uint32_t GetNSwitchPorts() const;
|
||||
|
||||
/**
|
||||
* \brief Gets the n-th switched port.
|
||||
* \param n the port index
|
||||
* \return the n-th switched NetDevice
|
||||
*/
|
||||
Ptr<NetDevice> GetSwitchPort(uint32_t n) const;
|
||||
|
||||
// inherited from NetDevice base class.
|
||||
void SetIfIndex(const uint32_t index) override;
|
||||
uint32_t GetIfIndex() const override;
|
||||
Ptr<Channel> GetChannel() const override;
|
||||
void SetAddress(Address address) override;
|
||||
Address GetAddress() const override;
|
||||
bool SetMtu(const uint16_t mtu) override;
|
||||
uint16_t GetMtu() const override;
|
||||
bool IsLinkUp() const override;
|
||||
void AddLinkChangeCallback(Callback<void> callback) override;
|
||||
bool IsBroadcast() const override;
|
||||
Address GetBroadcast() const override;
|
||||
bool IsMulticast() const override;
|
||||
Address GetMulticast(Ipv4Address multicastGroup) const override;
|
||||
bool IsPointToPoint() const override;
|
||||
bool IsBridge() const override;
|
||||
bool Send(Ptr<Packet> packet, const Address& dest, uint16_t protocolNumber) override;
|
||||
bool SendFrom(Ptr<Packet> packet,
|
||||
const Address& source,
|
||||
const Address& dest,
|
||||
uint16_t protocolNumber) override;
|
||||
Ptr<Node> GetNode() const override;
|
||||
void SetNode(Ptr<Node> node) override;
|
||||
bool NeedsArp() const override;
|
||||
void SetReceiveCallback(NetDevice::ReceiveCallback cb) override;
|
||||
void SetPromiscReceiveCallback(NetDevice::PromiscReceiveCallback cb) override;
|
||||
bool SupportsSendFrom() const override;
|
||||
Address GetMulticast(Ipv6Address addr) const override;
|
||||
|
||||
/**
|
||||
* \brief Add a entry to the forwarding table
|
||||
* \param dest destination mac
|
||||
* \param vid Vlan ID
|
||||
* \param outPorts vector of output port
|
||||
*/
|
||||
void AddForwardingTableEntry(Mac48Address dest,
|
||||
uint16_t vid,
|
||||
std::vector<Ptr<NetDevice>> outPorts);
|
||||
protected:
|
||||
void DoDispose() override;
|
||||
|
||||
/**
|
||||
* \brief Receives a packet from one switched port.
|
||||
* \param device the originating port
|
||||
* \param packet the received packet
|
||||
* \param protocol the packet protocol (e.g., Ethertype)
|
||||
* \param source the packet source
|
||||
* \param destination the packet destination
|
||||
* \param packetType the packet type (e.g., host, broadcast, etc.)
|
||||
*/
|
||||
void ReceiveFromDevice(Ptr<NetDevice> device,
|
||||
Ptr<const Packet> packet,
|
||||
uint16_t protocol,
|
||||
const Address& source,
|
||||
const Address& destination,
|
||||
PacketType packetType);
|
||||
|
||||
/**
|
||||
* \brief Forwards a packet
|
||||
* \param incomingPort the packet incoming port
|
||||
* \param packet the packet
|
||||
* \param protocol the packet protocol (e.g., Ethertype)
|
||||
* \param src the packet source
|
||||
* \param dst the packet destination
|
||||
*/
|
||||
void Forward(Ptr<NetDevice> incomingPort,
|
||||
Ptr<const Packet> packet,
|
||||
uint16_t protocol,
|
||||
Mac48Address src,
|
||||
Mac48Address dst);
|
||||
|
||||
/**
|
||||
* \brief Forwards a broadcast or a multicast packet
|
||||
* \param incomingPort the packet incoming port
|
||||
* \param packet the packet
|
||||
* \param protocol the packet protocol (e.g., Ethertype)
|
||||
* \param src the packet source
|
||||
* \param dst the packet destination
|
||||
*/
|
||||
void ForwardBroadcast(Ptr<NetDevice> incomingPort,
|
||||
Ptr<const Packet> packet,
|
||||
uint16_t protocol,
|
||||
Mac48Address src,
|
||||
Mac48Address dst);
|
||||
|
||||
/**
|
||||
* \brief Get the output ports from the forwarding table
|
||||
* \param dest destination mac
|
||||
* \param vid Vlan ID
|
||||
* \return output ports
|
||||
*/
|
||||
std::vector<Ptr<NetDevice>> GetOutputPortsFromForwardingTable(Mac48Address dest,
|
||||
uint16_t vid);
|
||||
|
||||
|
||||
|
||||
private:
|
||||
NetDevice::ReceiveCallback m_rxCallback; //!< receive callback
|
||||
NetDevice::PromiscReceiveCallback m_promiscRxCallback; //!< promiscuous receive callback
|
||||
|
||||
Mac48Address m_address; //!< MAC address of the NetDevice
|
||||
|
||||
/**
|
||||
* \ingroup ethernet
|
||||
* Structure holding the association between ports and vid for a mac destination address
|
||||
*/
|
||||
struct PortsToVidAssociation
|
||||
{
|
||||
Mac48Address dest;
|
||||
uint16_t vid;
|
||||
std::vector<Ptr<NetDevice>> associatedPorts;
|
||||
};
|
||||
|
||||
std::vector<PortsToVidAssociation> m_forwardingTable; //!< Container for forwarding table
|
||||
Ptr<Node> m_node; //!< node owning this NetDevice
|
||||
Ptr<SwitchChannel> m_channel; //!< virtual bridged channel
|
||||
std::vector<Ptr<NetDevice>> m_ports; //!< switched ports
|
||||
uint32_t m_ifIndex; //!< Interface index
|
||||
uint16_t m_mtu; //!< MTU of the switched NetDevice
|
||||
|
||||
Time m_minForwardingLatency;
|
||||
Time m_maxForwardingLatency;
|
||||
|
||||
uint16_t m_maxPortNumber;
|
||||
uint16_t m_maxFdbEntryNumber;
|
||||
|
||||
};
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif /* SWITCH_NET_DEVICE_H */
|
||||
1036
contrib/ethernet/test/ethernet-test-suite.cc
Normal file
1036
contrib/ethernet/test/ethernet-test-suite.cc
Normal file
File diff suppressed because it is too large
Load Diff
26
contrib/ethernet/test/examples-to-run.py
Normal file
26
contrib/ethernet/test/examples-to-run.py
Normal file
@@ -0,0 +1,26 @@
|
||||
#! /usr/bin/env python3
|
||||
|
||||
# A list of C++ examples to run in order to ensure that they remain
|
||||
# buildable and runnable over time. Each tuple in the list contains
|
||||
#
|
||||
# (example_name, do_run, do_valgrind_run).
|
||||
#
|
||||
# See test.py for more information.
|
||||
cpp_examples = [
|
||||
("ethernet-point2point", "True", "True"),
|
||||
("ethernet-point2point-withPropagationDelay", "True", "True"),
|
||||
("ethernet-point2point-withSmallFifo", "True", "True"),
|
||||
("ethernet-point2point-10Gb", "True", "True"),
|
||||
("ethernet-switched", "True", "True"),
|
||||
("ethernet-switched-withLatencyCallback", "True", "True"),
|
||||
("ethernet-switched-withPcap", "True", "True"),
|
||||
("ethernet-switched-withRxTxCallback", "True", "True"),
|
||||
]
|
||||
|
||||
# A list of Python examples to run in order to ensure that they remain
|
||||
# runnable over time. Each tuple in the list contains
|
||||
#
|
||||
# (example_name, do_run).
|
||||
#
|
||||
# See test.py for more information.
|
||||
python_examples = []
|
||||
24
contrib/real-device/CMakeLists.txt
Normal file
24
contrib/real-device/CMakeLists.txt
Normal file
@@ -0,0 +1,24 @@
|
||||
check_include_file_cxx(stdint.h HAVE_STDINT_H)
|
||||
if(HAVE_STDINT_H)
|
||||
add_definitions(-DHAVE_STDINT_H)
|
||||
endif()
|
||||
|
||||
set(examples_as_tests_sources)
|
||||
if(${ENABLE_EXAMPLES})
|
||||
set(examples_as_tests_sources
|
||||
#test/real-device-examples-test-suite.cc
|
||||
)
|
||||
endif()
|
||||
|
||||
build_lib(
|
||||
LIBNAME real-device
|
||||
SOURCE_FILES model/evb-lan9668.cc
|
||||
helper/real-device-helper.cc
|
||||
HEADER_FILES model/evb-lan9668.h
|
||||
helper/real-device-helper.h
|
||||
LIBRARIES_TO_LINK ${libcore}
|
||||
${libethernet}
|
||||
${libtsn}
|
||||
TEST_SOURCES test/real-device-test-suite.cc
|
||||
${examples_as_tests_sources}
|
||||
)
|
||||
22
contrib/real-device/examples/CMakeLists.txt
Normal file
22
contrib/real-device/examples/CMakeLists.txt
Normal file
@@ -0,0 +1,22 @@
|
||||
set(base_examples
|
||||
evb-lan9668-sp
|
||||
evb-lan9668-cbs
|
||||
evb-lan9668-tas
|
||||
evb-lan9668-psfp
|
||||
evb-lan9668-frer
|
||||
)
|
||||
foreach(
|
||||
example
|
||||
${base_examples}
|
||||
)
|
||||
build_lib_example(
|
||||
NAME ${example}
|
||||
SOURCE_FILES ${example}.cc
|
||||
LIBRARIES_TO_LINK ${libtsn}
|
||||
${libcore}
|
||||
${libnetwork}
|
||||
${libtraffic-generator}
|
||||
${libethernet}
|
||||
${libreal-device}
|
||||
)
|
||||
endforeach()
|
||||
158
contrib/real-device/examples/evb-lan9668-cbs.cc
Normal file
158
contrib/real-device/examples/evb-lan9668-cbs.cc
Normal file
@@ -0,0 +1,158 @@
|
||||
#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/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/evb-lan9668.h"
|
||||
#include "ns3/stream-identification-function-null.h"
|
||||
#include "ns3/frer-match-recovery-function.h"
|
||||
#include "ns3/frer-vector-recovery-function.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example with 4ES connected to 1SW in a 1Gb/s full duplex link as follow.
|
||||
* ES1 === \ / === ES2
|
||||
* SW
|
||||
* ES3 === / \ === ES4
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
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 !");
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
//Enable logging
|
||||
LogComponentEnable("Example", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("EthernetGenerator", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("EvbLan9668", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("TsnNetDevice", LOG_LEVEL_INFO);
|
||||
|
||||
CommandLine cmd(__FILE__);
|
||||
cmd.Parse(argc, argv);
|
||||
|
||||
//Create four end stations
|
||||
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
|
||||
Names::Add("ES1", n1);
|
||||
Ptr<TsnNode> n2 = CreateObject<TsnNode>();
|
||||
Names::Add("ES2", n2);
|
||||
Ptr<TsnNode> n3 = CreateObject<TsnNode>();
|
||||
Names::Add("ES3", n3);
|
||||
Ptr<TsnNode> n4 = CreateObject<TsnNode>();
|
||||
Names::Add("ES4", n4);
|
||||
|
||||
//Create and add a netDevices to each end station
|
||||
Ptr<TsnNetDevice> net1 = CreateObject<TsnNetDevice>();
|
||||
n1->AddDevice(net1);
|
||||
Names::Add("ES1e#01", net1);
|
||||
Ptr<TsnNetDevice> net2 = CreateObject<TsnNetDevice>();
|
||||
n2->AddDevice(net2);
|
||||
Names::Add("ES2#01", net2);
|
||||
Ptr<TsnNetDevice> net3 = CreateObject<TsnNetDevice>();
|
||||
n3->AddDevice(net3);
|
||||
Names::Add("ES3#01", net3);
|
||||
Ptr<TsnNetDevice> net4 = CreateObject<TsnNetDevice>();
|
||||
n4->AddDevice(net4);
|
||||
Names::Add("ES4#01", net4);
|
||||
|
||||
//Allocate a Mac address to the end station
|
||||
net1->SetAddress(Mac48Address::Allocate());
|
||||
net2->SetAddress(Mac48Address::Allocate());
|
||||
net3->SetAddress(Mac48Address::Allocate());
|
||||
net4->SetAddress(Mac48Address::Allocate());
|
||||
|
||||
//Create the switch
|
||||
Ptr<EvbLan9668> lan9668 = CreateObject<EvbLan9668>("SW");
|
||||
lan9668->AddCbs(2, 4, DataRate("1Mb/s"), DataRate("1Gb/s")); //(uint32_t port_id, uint32_t queue_id, DataRate iddle_slope, DataRate port_transmit_rate)
|
||||
|
||||
|
||||
//Create Ethernet Channels and attach it to the netDevices
|
||||
Ptr<EthernetChannel> l0 = CreateObject<EthernetChannel>();
|
||||
l0->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
net1->Attach(l0);
|
||||
lan9668->GetPort(1)->Attach(l0);
|
||||
Ptr<EthernetChannel> l1 = CreateObject<EthernetChannel>();
|
||||
l1->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
net2->Attach(l1);
|
||||
lan9668->GetPort(2)->Attach(l1);
|
||||
Ptr<EthernetChannel> l2 = CreateObject<EthernetChannel>();
|
||||
l2->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
net3->Attach(l2);
|
||||
lan9668->GetPort(3)->Attach(l2);
|
||||
Ptr<EthernetChannel> l3 = CreateObject<EthernetChannel>();
|
||||
l3->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
net4->Attach(l3);
|
||||
lan9668->GetPort(4)->Attach(l3);
|
||||
|
||||
|
||||
//Create and add eight FIFO on each end station net device
|
||||
for (int i=0; i<8; i++)
|
||||
{
|
||||
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net2->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net3->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net4->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
}
|
||||
|
||||
//Add forwarding table entry
|
||||
lan9668->AddForwardingTableEntry(Mac48Address::ConvertFrom(net2->GetAddress()), 10, {2});
|
||||
lan9668->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 10, {2, 3, 4});
|
||||
lan9668->AddForwardingTableEntry(Mac48Address::ConvertFrom(net1->GetAddress()), 11, {1});
|
||||
lan9668->AddForwardingTableEntry(Mac48Address::ConvertFrom(net4->GetAddress()), 12, {4});
|
||||
lan9668->AddForwardingTableEntry(Mac48Address::ConvertFrom(net2->GetAddress()), 13, {2});
|
||||
lan9668->AddForwardingTableEntry(Mac48Address::ConvertFrom(net2->GetAddress()), 14, {2});
|
||||
|
||||
//Application description
|
||||
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
|
||||
app0->Setup(net1);
|
||||
app0->SetAttribute("BurstSize", UintegerValue(3));
|
||||
app0->SetAttribute("PayloadSize", UintegerValue(1478));
|
||||
app0->SetAttribute("Period", TimeValue(MilliSeconds(100)));
|
||||
app0->SetAttribute("PCP", UintegerValue(4));
|
||||
app0->SetAttribute("VlanID", UintegerValue(10));
|
||||
app0->SetAttribute("Address", AddressValue(Mac48Address::ConvertFrom(net2->GetAddress())));
|
||||
n1->AddApplication(app0);
|
||||
app0->SetStartTime(MilliSeconds(0));
|
||||
app0->SetStopTime(MilliSeconds(200));
|
||||
|
||||
//Callback to display the packet transmitted and received log
|
||||
net1->TraceConnectWithoutContext("PhyTxBegin", MakeBoundCallback(&PhyTxCallback, Names::FindName(n1) + ":" + Names::FindName(net1)));
|
||||
net2->TraceConnectWithoutContext("MacRx", MakeBoundCallback(&MacRxCallback, Names::FindName(n2) + ":" + Names::FindName(net2)));
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(MilliSeconds(300));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
217
contrib/real-device/examples/evb-lan9668-frer.cc
Normal file
217
contrib/real-device/examples/evb-lan9668-frer.cc
Normal file
@@ -0,0 +1,217 @@
|
||||
#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/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/evb-lan9668.h"
|
||||
#include "ns3/stream-identification-function-null.h"
|
||||
#include "ns3/frer-match-recovery-function.h"
|
||||
#include "ns3/frer-vector-recovery-function.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example with 4ES connected to 2SW in a 1Gb/s full duplex link as follow.
|
||||
* ES1 === \ /===\ / === ES2
|
||||
* SW1 SW2
|
||||
* ES3 === / \===/ \ === ES4
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
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 pkt elimination due to FRER
|
||||
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("EvbLan9668", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("TsnNetDevice", LOG_LEVEL_INFO);
|
||||
|
||||
CommandLine cmd(__FILE__);
|
||||
cmd.Parse(argc, argv);
|
||||
|
||||
//Create four end stations
|
||||
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
|
||||
Names::Add("ES1", n1);
|
||||
Ptr<TsnNode> n2 = CreateObject<TsnNode>();
|
||||
Names::Add("ES2", n2);
|
||||
Ptr<TsnNode> n3 = CreateObject<TsnNode>();
|
||||
Names::Add("ES3", n3);
|
||||
Ptr<TsnNode> n4 = CreateObject<TsnNode>();
|
||||
Names::Add("ES4", n4);
|
||||
|
||||
//Create and add a netDevices to each end station
|
||||
Ptr<TsnNetDevice> net1 = CreateObject<TsnNetDevice>();
|
||||
n1->AddDevice(net1);
|
||||
Names::Add("ES1e#01", net1);
|
||||
Ptr<TsnNetDevice> net2 = CreateObject<TsnNetDevice>();
|
||||
n2->AddDevice(net2);
|
||||
Names::Add("ES2#01", net2);
|
||||
Ptr<TsnNetDevice> net3 = CreateObject<TsnNetDevice>();
|
||||
n3->AddDevice(net3);
|
||||
Names::Add("ES3#01", net3);
|
||||
Ptr<TsnNetDevice> net4 = CreateObject<TsnNetDevice>();
|
||||
n4->AddDevice(net4);
|
||||
Names::Add("ES4#01", net4);
|
||||
|
||||
//Allocate a Mac address to the end station
|
||||
net1->SetAddress(Mac48Address::Allocate());
|
||||
net2->SetAddress(Mac48Address::Allocate());
|
||||
net3->SetAddress(Mac48Address::Allocate());
|
||||
net4->SetAddress(Mac48Address::Allocate());
|
||||
|
||||
//Create the switch
|
||||
Ptr<EvbLan9668> lan9668_1 = CreateObject<EvbLan9668>("SW1");
|
||||
Ptr<EvbLan9668> lan9668_2 = CreateObject<EvbLan9668>("SW2");
|
||||
|
||||
//Create Ethernet Channels and attach it to the netDevices
|
||||
Ptr<EthernetChannel> l0 = CreateObject<EthernetChannel>();
|
||||
l0->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
net1->Attach(l0);
|
||||
lan9668_1->GetPort(1)->Attach(l0);
|
||||
Ptr<EthernetChannel> l1 = CreateObject<EthernetChannel>();
|
||||
l1->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
net2->Attach(l1);
|
||||
lan9668_2->GetPort(2)->Attach(l1);
|
||||
Ptr<EthernetChannel> l2 = CreateObject<EthernetChannel>();
|
||||
l2->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
net3->Attach(l2);
|
||||
lan9668_2->GetPort(1)->Attach(l2);
|
||||
Ptr<EthernetChannel> l3 = CreateObject<EthernetChannel>();
|
||||
l3->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
net4->Attach(l3);
|
||||
lan9668_1->GetPort(2)->Attach(l3);
|
||||
Ptr<EthernetChannel> l4 = CreateObject<EthernetChannel>();
|
||||
l4->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
lan9668_1->GetPort(3)->Attach(l4);
|
||||
lan9668_2->GetPort(3)->Attach(l4);
|
||||
Ptr<EthernetChannel> l5 = CreateObject<EthernetChannel>();
|
||||
l5->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
lan9668_1->GetPort(4)->Attach(l5);
|
||||
lan9668_2->GetPort(4)->Attach(l5);
|
||||
|
||||
|
||||
//Create and add eight FIFO on each end station net device
|
||||
for (int i=0; i<8; i++)
|
||||
{
|
||||
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net2->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net3->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net4->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
}
|
||||
|
||||
//Add forwarding table entry
|
||||
lan9668_1->AddForwardingTableEntry(Mac48Address::ConvertFrom(net2->GetAddress()), 10, {3,4});
|
||||
lan9668_2->AddForwardingTableEntry(Mac48Address::ConvertFrom(net2->GetAddress()), 10, {2});
|
||||
|
||||
|
||||
//SW1 Stream identification and FRER configuration (replication)
|
||||
//Stream identification
|
||||
uint32_t streamHandle = 1;
|
||||
Ptr<NullStreamIdentificationFunction> sif0 = CreateObject<NullStreamIdentificationFunction>();
|
||||
sif0->SetAttribute("VlanID", UintegerValue(10));
|
||||
sif0->SetAttribute("Address", AddressValue(Mac48Address::ConvertFrom(net2->GetAddress())));
|
||||
lan9668_1->AddNullStreamIdentificationFunction(streamHandle, sif0, {1}, {}, {}, {});
|
||||
//Sequencing : Sequence generation
|
||||
Ptr<SequenceGenerationFunction> seqf0 = CreateObject<SequenceGenerationFunction>();
|
||||
seqf0->SetAttribute("Direction", BooleanValue(false)); //in-facing
|
||||
seqf0->SetStreamHandle({streamHandle});
|
||||
lan9668_1->AddSequenceGenerationFunction(seqf0);
|
||||
//Sequence encode
|
||||
Ptr<SequenceEncodeDecodeFunction> seqEnc0 = CreateObject<SequenceEncodeDecodeFunction>();
|
||||
seqEnc0->SetAttribute("Direction", BooleanValue(false)); //in-facing
|
||||
seqEnc0->SetAttribute("Active", BooleanValue(true));
|
||||
seqEnc0->SetStreamHandle({streamHandle});
|
||||
lan9668_1->AddSequenceEncodeDecodeFunction(seqEnc0, 1);
|
||||
|
||||
|
||||
//SW2 Stream identification adn FRER configuration (elimination)
|
||||
//Stream identification
|
||||
Ptr<NullStreamIdentificationFunction> sif1 = CreateObject<NullStreamIdentificationFunction>();
|
||||
sif1->SetAttribute("VlanID", UintegerValue(10));
|
||||
sif1->SetAttribute("Address", AddressValue(Mac48Address::ConvertFrom(net2->GetAddress())));
|
||||
lan9668_2->AddNullStreamIdentificationFunction(streamHandle, sif1, {}, {}, {2}, {});
|
||||
//Sequence Decode
|
||||
Ptr<SequenceEncodeDecodeFunction> seqEnc1 = CreateObject<SequenceEncodeDecodeFunction>();
|
||||
seqEnc1->SetAttribute("Direction", BooleanValue(false)); //in-facing
|
||||
seqEnc1->SetAttribute("Active", BooleanValue(false));
|
||||
seqEnc1->SetStreamHandle({streamHandle});
|
||||
lan9668_2->AddSequenceEncodeDecodeFunction(seqEnc1, 2);
|
||||
//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});
|
||||
//Sequencing : Sequence recovery : recovery function
|
||||
Ptr<MatchRecoveryFunction> recf0 = CreateObject<MatchRecoveryFunction>();
|
||||
recf0->SetAttribute("ResetTimer", TimeValue(Seconds(1)));
|
||||
//Sequencing : Sequence recovery : latent error detection function
|
||||
Ptr<LatentErrorDetectionFunction> latf0 = CreateObject<LatentErrorDetectionFunction>();
|
||||
latf0->SetAttribute("LatentErrorPaths", UintegerValue(2));
|
||||
lan9668_2->AddSequenceRecoveryFunction(seqfreco0, recf0, latf0, {2});
|
||||
|
||||
//Application description
|
||||
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
|
||||
app0->Setup(net1);
|
||||
app0->SetAttribute("BurstSize", UintegerValue(1));
|
||||
app0->SetAttribute("PayloadSize", UintegerValue(1478));
|
||||
app0->SetAttribute("Period", TimeValue(MilliSeconds(100)));
|
||||
app0->SetAttribute("PCP", UintegerValue(4));
|
||||
app0->SetAttribute("VlanID", UintegerValue(10));
|
||||
app0->SetAttribute("Address", AddressValue(Mac48Address::ConvertFrom(net2->GetAddress())));
|
||||
n1->AddApplication(app0);
|
||||
app0->SetStartTime(MilliSeconds(0));
|
||||
app0->SetStopTime(MilliSeconds(200));
|
||||
|
||||
//Callback to display the packet transmitted and received log
|
||||
net1->TraceConnectWithoutContext("PhyTxBegin", MakeBoundCallback(&PhyTxCallback, Names::FindName(n1) + ":" + Names::FindName(net1)));
|
||||
net2->TraceConnectWithoutContext("MacRx", MakeBoundCallback(&MacRxCallback, Names::FindName(n2) + ":" + Names::FindName(net2)));
|
||||
|
||||
//Callback to display elimination event
|
||||
lan9668_2->GetPort(2)->TraceConnectWithoutContext("FrerDrop", MakeBoundCallback(&FrerDrop, Names::FindName(lan9668_2->GetPort(2))));
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(MilliSeconds(300));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
194
contrib/real-device/examples/evb-lan9668-psfp.cc
Normal file
194
contrib/real-device/examples/evb-lan9668-psfp.cc
Normal file
@@ -0,0 +1,194 @@
|
||||
#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/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/evb-lan9668.h"
|
||||
#include "ns3/stream-identification-function-null.h"
|
||||
#include "ns3/frer-match-recovery-function.h"
|
||||
#include "ns3/frer-vector-recovery-function.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example with 4ES connected to 1SW in a 1Gb/s full duplex link as follow.
|
||||
* ES1 === \ / === ES2
|
||||
* SW
|
||||
* ES3 === / \ === ES4
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
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 !");
|
||||
}
|
||||
|
||||
//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("EthernetGenerator", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("EvbLan9668", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("TsnNetDevice", LOG_LEVEL_INFO);
|
||||
|
||||
CommandLine cmd(__FILE__);
|
||||
cmd.Parse(argc, argv);
|
||||
|
||||
//Create four end stations
|
||||
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
|
||||
Names::Add("ES1", n1);
|
||||
Ptr<TsnNode> n2 = CreateObject<TsnNode>();
|
||||
Names::Add("ES2", n2);
|
||||
Ptr<TsnNode> n3 = CreateObject<TsnNode>();
|
||||
Names::Add("ES3", n3);
|
||||
Ptr<TsnNode> n4 = CreateObject<TsnNode>();
|
||||
Names::Add("ES4", n4);
|
||||
|
||||
//Create and add a netDevices to each end station
|
||||
Ptr<TsnNetDevice> net1 = CreateObject<TsnNetDevice>();
|
||||
n1->AddDevice(net1);
|
||||
Names::Add("ES1e#01", net1);
|
||||
Ptr<TsnNetDevice> net2 = CreateObject<TsnNetDevice>();
|
||||
n2->AddDevice(net2);
|
||||
Names::Add("ES2#01", net2);
|
||||
Ptr<TsnNetDevice> net3 = CreateObject<TsnNetDevice>();
|
||||
n3->AddDevice(net3);
|
||||
Names::Add("ES3#01", net3);
|
||||
Ptr<TsnNetDevice> net4 = CreateObject<TsnNetDevice>();
|
||||
n4->AddDevice(net4);
|
||||
Names::Add("ES4#01", net4);
|
||||
|
||||
//Allocate a Mac address to the end station
|
||||
net1->SetAddress(Mac48Address::Allocate());
|
||||
net2->SetAddress(Mac48Address::Allocate());
|
||||
net3->SetAddress(Mac48Address::Allocate());
|
||||
net4->SetAddress(Mac48Address::Allocate());
|
||||
|
||||
//Create the switch
|
||||
Ptr<EvbLan9668> lan9668 = CreateObject<EvbLan9668>("SW");
|
||||
|
||||
//Create Ethernet Channels and attach it to the netDevices
|
||||
Ptr<EthernetChannel> l0 = CreateObject<EthernetChannel>();
|
||||
l0->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
net1->Attach(l0);
|
||||
lan9668->GetPort(1)->Attach(l0);
|
||||
Ptr<EthernetChannel> l1 = CreateObject<EthernetChannel>();
|
||||
l1->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
net2->Attach(l1);
|
||||
lan9668->GetPort(2)->Attach(l1);
|
||||
Ptr<EthernetChannel> l2 = CreateObject<EthernetChannel>();
|
||||
l2->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
net3->Attach(l2);
|
||||
lan9668->GetPort(3)->Attach(l2);
|
||||
Ptr<EthernetChannel> l3 = CreateObject<EthernetChannel>();
|
||||
l3->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
net4->Attach(l3);
|
||||
lan9668->GetPort(4)->Attach(l3);
|
||||
|
||||
|
||||
//Create and add eight FIFO on each end station net device
|
||||
for (int i=0; i<8; i++)
|
||||
{
|
||||
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net2->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net3->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net4->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
}
|
||||
|
||||
//Add forwarding table entry
|
||||
lan9668->AddForwardingTableEntry(Mac48Address::ConvertFrom(net2->GetAddress()), 10, {2});
|
||||
lan9668->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 10, {2, 3, 4});
|
||||
lan9668->AddForwardingTableEntry(Mac48Address::ConvertFrom(net1->GetAddress()), 11, {1});
|
||||
lan9668->AddForwardingTableEntry(Mac48Address::ConvertFrom(net4->GetAddress()), 12, {4});
|
||||
lan9668->AddForwardingTableEntry(Mac48Address::ConvertFrom(net2->GetAddress()), 13, {2});
|
||||
lan9668->AddForwardingTableEntry(Mac48Address::ConvertFrom(net2->GetAddress()), 14, {2});
|
||||
|
||||
|
||||
//Add a null stream identification function on the switch for psfp
|
||||
Ptr<NullStreamIdentificationFunction> sif = CreateObject<NullStreamIdentificationFunction>();
|
||||
sif->SetAttribute("VlanID", UintegerValue(10));
|
||||
sif->SetAttribute("Address", AddressValue(Mac48Address::ConvertFrom(net2->GetAddress())));
|
||||
lan9668->AddNullStreamIdentificationFunction(112, sif, {1}, {}, {}, {});
|
||||
|
||||
//Configure PSFP on the switch
|
||||
Ptr<StreamFilterInstance> sfi0 = CreateObject<StreamFilterInstance>();
|
||||
sfi0->SetAttribute("StreamHandle", IntegerValue(112));
|
||||
sfi0->SetAttribute("Priority", IntegerValue(-1)); //-1 = wildcard (like in PSFP MIB)
|
||||
sfi0->SetAttribute("MaxSDUSize", UintegerValue(1500));
|
||||
lan9668->AddStreamFilter(sfi0);
|
||||
Ptr<FlowMeterInstance> fm0 = CreateObject<FlowMeterInstance>();
|
||||
fm0->SetAttribute("CIR", DataRateValue(DataRate("40Mb/s")));
|
||||
fm0->SetAttribute("CBS", UintegerValue(1500));
|
||||
fm0->SetAttribute("DropOnYellow", BooleanValue(true));
|
||||
fm0->SetAttribute("MarkAllFramesRedEnable", BooleanValue(false));
|
||||
uint16_t fmid = lan9668->AddFlowMeter(fm0);
|
||||
sfi0->AddFlowMeterInstanceId(fmid);
|
||||
|
||||
//Application description
|
||||
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
|
||||
app0->Setup(net1);
|
||||
app0->SetAttribute("BurstSize", UintegerValue(1));
|
||||
app0->SetAttribute("PayloadSize", UintegerValue(1478));
|
||||
app0->SetAttribute("Period", TimeValue(MilliSeconds(100)));
|
||||
app0->SetAttribute("PCP", UintegerValue(4));
|
||||
app0->SetAttribute("VlanID", UintegerValue(10));
|
||||
app0->SetAttribute("Address", AddressValue(Mac48Address::ConvertFrom(net2->GetAddress())));
|
||||
n1->AddApplication(app0);
|
||||
app0->SetStartTime(MilliSeconds(0));
|
||||
app0->SetStopTime(MilliSeconds(200));
|
||||
|
||||
//Callback to display the packet transmitted and received log
|
||||
net1->TraceConnectWithoutContext("PhyTxBegin", MakeBoundCallback(&PhyTxCallback, Names::FindName(n1) + ":" + Names::FindName(net1)));
|
||||
net2->TraceConnectWithoutContext("MacRx", MakeBoundCallback(&MacRxCallback, Names::FindName(n2) + ":" + Names::FindName(net2)));
|
||||
|
||||
//Callback related to PSFP event
|
||||
lan9668->GetPort(1)->TraceConnectWithoutContext("MaxSDUSizeFilterDrop", MakeBoundCallback(&MaxSDUSizeFilterDrop, Names::FindName(lan9668->GetPort(1))));
|
||||
lan9668->GetPort(1)->TraceConnectWithoutContext("REDFrameDrop", MakeBoundCallback(&REDFrameDrop, Names::FindName(lan9668->GetPort(1))));
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(MilliSeconds(300));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
156
contrib/real-device/examples/evb-lan9668-sp.cc
Normal file
156
contrib/real-device/examples/evb-lan9668-sp.cc
Normal file
@@ -0,0 +1,156 @@
|
||||
#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/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/evb-lan9668.h"
|
||||
#include "ns3/stream-identification-function-null.h"
|
||||
#include "ns3/frer-match-recovery-function.h"
|
||||
#include "ns3/frer-vector-recovery-function.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example with 4ES connected to 1SW in a 1Gb/s full duplex link as follow.
|
||||
* ES1 === \ / === ES2
|
||||
* SW
|
||||
* ES3 === / \ === ES4
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
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 !");
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
//Enable logging
|
||||
LogComponentEnable("Example", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("EthernetGenerator", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("EvbLan9668", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("TsnNetDevice", LOG_LEVEL_INFO);
|
||||
|
||||
CommandLine cmd(__FILE__);
|
||||
cmd.Parse(argc, argv);
|
||||
|
||||
//Create four end stations
|
||||
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
|
||||
Names::Add("ES1", n1);
|
||||
Ptr<TsnNode> n2 = CreateObject<TsnNode>();
|
||||
Names::Add("ES2", n2);
|
||||
Ptr<TsnNode> n3 = CreateObject<TsnNode>();
|
||||
Names::Add("ES3", n3);
|
||||
Ptr<TsnNode> n4 = CreateObject<TsnNode>();
|
||||
Names::Add("ES4", n4);
|
||||
|
||||
//Create and add a netDevices to each end station
|
||||
Ptr<TsnNetDevice> net1 = CreateObject<TsnNetDevice>();
|
||||
n1->AddDevice(net1);
|
||||
Names::Add("ES1e#01", net1);
|
||||
Ptr<TsnNetDevice> net2 = CreateObject<TsnNetDevice>();
|
||||
n2->AddDevice(net2);
|
||||
Names::Add("ES2#01", net2);
|
||||
Ptr<TsnNetDevice> net3 = CreateObject<TsnNetDevice>();
|
||||
n3->AddDevice(net3);
|
||||
Names::Add("ES3#01", net3);
|
||||
Ptr<TsnNetDevice> net4 = CreateObject<TsnNetDevice>();
|
||||
n4->AddDevice(net4);
|
||||
Names::Add("ES4#01", net4);
|
||||
|
||||
//Allocate a Mac address to the end station
|
||||
net1->SetAddress(Mac48Address::Allocate());
|
||||
net2->SetAddress(Mac48Address::Allocate());
|
||||
net3->SetAddress(Mac48Address::Allocate());
|
||||
net4->SetAddress(Mac48Address::Allocate());
|
||||
|
||||
//Create the switch
|
||||
Ptr<EvbLan9668> lan9668 = CreateObject<EvbLan9668>("SW");
|
||||
|
||||
//Create Ethernet Channels and attach it to the netDevices
|
||||
Ptr<EthernetChannel> l0 = CreateObject<EthernetChannel>();
|
||||
l0->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
net1->Attach(l0);
|
||||
lan9668->GetPort(1)->Attach(l0);
|
||||
Ptr<EthernetChannel> l1 = CreateObject<EthernetChannel>();
|
||||
l1->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
net2->Attach(l1);
|
||||
lan9668->GetPort(2)->Attach(l1);
|
||||
Ptr<EthernetChannel> l2 = CreateObject<EthernetChannel>();
|
||||
l2->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
net3->Attach(l2);
|
||||
lan9668->GetPort(3)->Attach(l2);
|
||||
Ptr<EthernetChannel> l3 = CreateObject<EthernetChannel>();
|
||||
l3->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
net4->Attach(l3);
|
||||
lan9668->GetPort(4)->Attach(l3);
|
||||
|
||||
|
||||
//Create and add eight FIFO on each end station net device
|
||||
for (int i=0; i<8; i++)
|
||||
{
|
||||
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net2->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net3->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net4->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
}
|
||||
|
||||
//Add forwarding table entry
|
||||
lan9668->AddForwardingTableEntry(Mac48Address::ConvertFrom(net2->GetAddress()), 10, {2});
|
||||
lan9668->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 10, {2, 3, 4});
|
||||
lan9668->AddForwardingTableEntry(Mac48Address::ConvertFrom(net1->GetAddress()), 11, {1});
|
||||
lan9668->AddForwardingTableEntry(Mac48Address::ConvertFrom(net4->GetAddress()), 12, {4});
|
||||
lan9668->AddForwardingTableEntry(Mac48Address::ConvertFrom(net2->GetAddress()), 13, {2});
|
||||
lan9668->AddForwardingTableEntry(Mac48Address::ConvertFrom(net2->GetAddress()), 14, {2});
|
||||
|
||||
//Application description
|
||||
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
|
||||
app0->Setup(net1);
|
||||
app0->SetAttribute("BurstSize", UintegerValue(1));
|
||||
app0->SetAttribute("PayloadSize", UintegerValue(1478));
|
||||
app0->SetAttribute("Period", TimeValue(MilliSeconds(100)));
|
||||
app0->SetAttribute("PCP", UintegerValue(4));
|
||||
app0->SetAttribute("VlanID", UintegerValue(10));
|
||||
app0->SetAttribute("Address", AddressValue(Mac48Address::ConvertFrom(net2->GetAddress())));
|
||||
n1->AddApplication(app0);
|
||||
app0->SetStartTime(MilliSeconds(0));
|
||||
app0->SetStopTime(MilliSeconds(200));
|
||||
|
||||
//Callback to display the packet transmitted and received log
|
||||
net1->TraceConnectWithoutContext("PhyTxBegin", MakeBoundCallback(&PhyTxCallback, Names::FindName(n1) + ":" + Names::FindName(net1)));
|
||||
net2->TraceConnectWithoutContext("MacRx", MakeBoundCallback(&MacRxCallback, Names::FindName(n2) + ":" + Names::FindName(net2)));
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(MilliSeconds(300));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
160
contrib/real-device/examples/evb-lan9668-tas.cc
Normal file
160
contrib/real-device/examples/evb-lan9668-tas.cc
Normal file
@@ -0,0 +1,160 @@
|
||||
#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/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/evb-lan9668.h"
|
||||
#include "ns3/stream-identification-function-null.h"
|
||||
#include "ns3/frer-match-recovery-function.h"
|
||||
#include "ns3/frer-vector-recovery-function.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example with 4ES connected to 1SW in a 1Gb/s full duplex link as follow.
|
||||
* ES1 === \ / === ES2
|
||||
* SW
|
||||
* ES3 === / \ === ES4
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
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 !");
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
//Enable logging
|
||||
LogComponentEnable("Example", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("EthernetGenerator", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("EvbLan9668", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("TsnNetDevice", LOG_LEVEL_INFO);
|
||||
|
||||
CommandLine cmd(__FILE__);
|
||||
cmd.Parse(argc, argv);
|
||||
|
||||
//Create four end stations
|
||||
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
|
||||
Names::Add("ES1", n1);
|
||||
Ptr<TsnNode> n2 = CreateObject<TsnNode>();
|
||||
Names::Add("ES2", n2);
|
||||
Ptr<TsnNode> n3 = CreateObject<TsnNode>();
|
||||
Names::Add("ES3", n3);
|
||||
Ptr<TsnNode> n4 = CreateObject<TsnNode>();
|
||||
Names::Add("ES4", n4);
|
||||
|
||||
//Create and add a netDevices to each end station
|
||||
Ptr<TsnNetDevice> net1 = CreateObject<TsnNetDevice>();
|
||||
n1->AddDevice(net1);
|
||||
Names::Add("ES1e#01", net1);
|
||||
Ptr<TsnNetDevice> net2 = CreateObject<TsnNetDevice>();
|
||||
n2->AddDevice(net2);
|
||||
Names::Add("ES2#01", net2);
|
||||
Ptr<TsnNetDevice> net3 = CreateObject<TsnNetDevice>();
|
||||
n3->AddDevice(net3);
|
||||
Names::Add("ES3#01", net3);
|
||||
Ptr<TsnNetDevice> net4 = CreateObject<TsnNetDevice>();
|
||||
n4->AddDevice(net4);
|
||||
Names::Add("ES4#01", net4);
|
||||
|
||||
//Allocate a Mac address to the end station
|
||||
net1->SetAddress(Mac48Address::Allocate());
|
||||
net2->SetAddress(Mac48Address::Allocate());
|
||||
net3->SetAddress(Mac48Address::Allocate());
|
||||
net4->SetAddress(Mac48Address::Allocate());
|
||||
|
||||
//Create the switch
|
||||
Ptr<EvbLan9668> lan9668 = CreateObject<EvbLan9668>("SW");
|
||||
lan9668->AddGclEntry(2,MilliSeconds(200), 1); //uint32_t port_id, Time interval, uint8_t state
|
||||
lan9668->AddGclEntry(2,MilliSeconds(200), 16);
|
||||
lan9668->StartTas();
|
||||
|
||||
|
||||
//Create Ethernet Channels and attach it to the netDevices
|
||||
Ptr<EthernetChannel> l0 = CreateObject<EthernetChannel>();
|
||||
l0->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
net1->Attach(l0);
|
||||
lan9668->GetPort(1)->Attach(l0);
|
||||
Ptr<EthernetChannel> l1 = CreateObject<EthernetChannel>();
|
||||
l1->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
net2->Attach(l1);
|
||||
lan9668->GetPort(2)->Attach(l1);
|
||||
Ptr<EthernetChannel> l2 = CreateObject<EthernetChannel>();
|
||||
l2->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
net3->Attach(l2);
|
||||
lan9668->GetPort(3)->Attach(l2);
|
||||
Ptr<EthernetChannel> l3 = CreateObject<EthernetChannel>();
|
||||
l3->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
net4->Attach(l3);
|
||||
lan9668->GetPort(4)->Attach(l3);
|
||||
|
||||
|
||||
//Create and add eight FIFO on each end station net device
|
||||
for (int i=0; i<8; i++)
|
||||
{
|
||||
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net2->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net3->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net4->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
}
|
||||
|
||||
//Add forwarding table entry
|
||||
lan9668->AddForwardingTableEntry(Mac48Address::ConvertFrom(net2->GetAddress()), 10, {2});
|
||||
lan9668->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 10, {2, 3, 4});
|
||||
lan9668->AddForwardingTableEntry(Mac48Address::ConvertFrom(net1->GetAddress()), 11, {1});
|
||||
lan9668->AddForwardingTableEntry(Mac48Address::ConvertFrom(net4->GetAddress()), 12, {4});
|
||||
lan9668->AddForwardingTableEntry(Mac48Address::ConvertFrom(net2->GetAddress()), 13, {2});
|
||||
lan9668->AddForwardingTableEntry(Mac48Address::ConvertFrom(net2->GetAddress()), 14, {2});
|
||||
|
||||
//Application description
|
||||
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
|
||||
app0->Setup(net1);
|
||||
app0->SetAttribute("BurstSize", UintegerValue(1));
|
||||
app0->SetAttribute("PayloadSize", UintegerValue(1478));
|
||||
app0->SetAttribute("Period", TimeValue(MilliSeconds(100)));
|
||||
app0->SetAttribute("PCP", UintegerValue(4));
|
||||
app0->SetAttribute("VlanID", UintegerValue(10));
|
||||
app0->SetAttribute("Address", AddressValue(Mac48Address::ConvertFrom(net2->GetAddress())));
|
||||
n1->AddApplication(app0);
|
||||
app0->SetStartTime(MilliSeconds(0));
|
||||
app0->SetStopTime(MilliSeconds(200));
|
||||
|
||||
//Callback to display the packet transmitted and received log
|
||||
net1->TraceConnectWithoutContext("PhyTxBegin", MakeBoundCallback(&PhyTxCallback, Names::FindName(n1) + ":" + Names::FindName(net1)));
|
||||
net2->TraceConnectWithoutContext("MacRx", MakeBoundCallback(&MacRxCallback, Names::FindName(n2) + ":" + Names::FindName(net2)));
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(MilliSeconds(300));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
8
contrib/real-device/helper/real-device-helper.cc
Normal file
8
contrib/real-device/helper/real-device-helper.cc
Normal file
@@ -0,0 +1,8 @@
|
||||
#include "real-device-helper.h"
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
/* ... */
|
||||
|
||||
}
|
||||
16
contrib/real-device/helper/real-device-helper.h
Normal file
16
contrib/real-device/helper/real-device-helper.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifndef REAL_DEVICE_HELPER_H
|
||||
#define REAL_DEVICE_HELPER_H
|
||||
|
||||
#include "ns3/evb-lan9668.h"
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
// Each class should be documented using Doxygen,
|
||||
// and have an \ingroup real-device directive
|
||||
|
||||
/* ... */
|
||||
|
||||
}
|
||||
|
||||
#endif /* REAL_DEVICE_HELPER_H */
|
||||
267
contrib/real-device/model/evb-lan9668.cc
Normal file
267
contrib/real-device/model/evb-lan9668.cc
Normal file
@@ -0,0 +1,267 @@
|
||||
#include "evb-lan9668.h"
|
||||
|
||||
#include "ns3/names.h"
|
||||
#include "ns3/drop-tail-queue.h"
|
||||
|
||||
#include "ns3/cbs.h"
|
||||
#include "ns3/tas.h"
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("EvbLan9668");
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED(EvbLan9668);
|
||||
|
||||
TypeId
|
||||
EvbLan9668::GetTypeId()
|
||||
{
|
||||
static TypeId tid =
|
||||
TypeId("ns3::EvbLan9668")
|
||||
.SetParent<Object>()
|
||||
.SetGroupName("real-device")
|
||||
.AddConstructor<EvbLan9668>();
|
||||
return tid;
|
||||
}
|
||||
|
||||
EvbLan9668::EvbLan9668()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
m_node = CreateObject<TsnNode>();
|
||||
m_node->AddClock(CreateObject<Clock>()); //Add perfect clock
|
||||
|
||||
for (int i=0; i<m_portNumber; ++i){
|
||||
Ptr<TsnNetDevice> net = CreateObject<TsnNetDevice>();
|
||||
for (int j=0; j<m_queuesPerPort; ++j){
|
||||
Ptr<DropTailQueue<Packet>> q = CreateObject<DropTailQueue<Packet>>();
|
||||
q->SetAttribute("MaxSize", QueueSizeValue(m_fifoSize));
|
||||
net->SetQueue(q);
|
||||
}
|
||||
m_node->AddDevice(net);
|
||||
m_net_devices.insert(m_net_devices.end(), net);
|
||||
}
|
||||
|
||||
m_switch_net_device = CreateObject<SwitchNetDevice>();
|
||||
m_switch_net_device->SetAddress(Mac48Address::Allocate());
|
||||
m_node->AddDevice(m_switch_net_device);
|
||||
for (int i = 0; i < (int)m_net_devices.size(); i++){
|
||||
m_switch_net_device->AddSwitchPort(m_net_devices[i]);
|
||||
}
|
||||
|
||||
m_node->AddDevice(m_switch_net_device);
|
||||
|
||||
SetHardwareLimits();
|
||||
}
|
||||
|
||||
EvbLan9668::EvbLan9668(std::string name): EvbLan9668()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
|
||||
Names::Add(name, m_node);
|
||||
for (int i = 0; i < (int)m_net_devices.size(); i++){
|
||||
Names::Add(name + "-" + std::to_string(i) , m_net_devices[i]);
|
||||
}
|
||||
}
|
||||
|
||||
EvbLan9668::~EvbLan9668()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
}
|
||||
|
||||
void
|
||||
EvbLan9668::SetHardwareLimits()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
//FDB
|
||||
m_switch_net_device->SetAttribute("MaxPortNumber", UintegerValue(m_portNumber));
|
||||
m_switch_net_device->SetAttribute("MaxFdbEntryNumber", UintegerValue(m_maxFdbEntryNumber));
|
||||
m_switch_net_device->SetAttribute("MinForwardingLatency", TimeValue(m_minForwardingLatency));
|
||||
m_switch_net_device->SetAttribute("MaxForwardingLatency", TimeValue(m_maxForwardingLatency));
|
||||
|
||||
//TAS
|
||||
for (int i = 0; i < (int)m_net_devices.size(); i++){
|
||||
m_net_devices[i]->GetTas()->SetAttribute("MaxGclEntryNumber", UintegerValue(m_maxGclEntryNumber));
|
||||
m_net_devices[i]->GetTas()->SetAttribute("MaxGclCycleDuration", TimeValue(m_maxGclCycleDuration));
|
||||
m_net_devices[i]->GetTas()->SetAttribute("MaxGclTimeInterval", TimeValue(m_maxGclTimeInterval));
|
||||
}
|
||||
|
||||
//Stream identification
|
||||
m_node->SetAttribute("MaxSidEntryNumber", UintegerValue(m_maxSidEntryNumber));
|
||||
|
||||
//PSFP
|
||||
m_node->SetAttribute("MaxPsfpFilterEntryNumber", UintegerValue(m_maxPsfpFilterEntryNumber));
|
||||
m_node->SetAttribute("MaxPsfpStreamGateEntryNumber", UintegerValue(m_maxPsfpStreamGateEntryNumber));
|
||||
m_node->SetAttribute("MaxPsfpFlowMeterEntryNumber", UintegerValue(m_maxPsfpFlowMeterEntryNumber));
|
||||
|
||||
//FRER
|
||||
m_node->SetAttribute("MaxFrerSeqGenEntryNumber", UintegerValue(m_maxFrerSeqGenEntryNumber));
|
||||
m_node->SetAttribute("MaxFrerSeqRcvyEntryNumber", UintegerValue(m_maxFrerSeqRcvyEntryNumber));
|
||||
m_node->SetAttribute("MaxFrerSeqEncEntryNumber", UintegerValue(m_maxFrerSeqEncEntryNumber));
|
||||
}
|
||||
|
||||
|
||||
Ptr<TsnNetDevice>
|
||||
EvbLan9668::GetPort(int port_id)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
NS_ASSERT(port_id < (int) m_net_devices.size());
|
||||
return m_net_devices[port_id];
|
||||
}
|
||||
|
||||
void
|
||||
EvbLan9668::SetPortDatarate(int port_id, DataRate d)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
NS_ASSERT_MSG(d == DataRate("10Mb/s") || d == DataRate("100Mb/s") || d == DataRate("1Gb/s"), "Trying to use a datarate not supported on this device (i.e 10Mb/s, 100Mb/s and 1Gb/s)");
|
||||
GetPort(port_id)->SetAttribute("DataRate", DataRateValue(d));
|
||||
}
|
||||
|
||||
void
|
||||
EvbLan9668::AddForwardingTableEntry(Mac48Address dest, uint16_t vlan_id, std::vector<uint32_t> output_port_ids){
|
||||
NS_LOG_FUNCTION(this);
|
||||
std::vector<Ptr<NetDevice>> output_ports = {};
|
||||
for (int i = 0; i < (int)output_port_ids.size(); i++){
|
||||
output_ports.insert(output_ports.end(), GetPort(output_port_ids[i]));
|
||||
}
|
||||
m_switch_net_device->AddForwardingTableEntry(dest, vlan_id, output_ports);
|
||||
}
|
||||
|
||||
void
|
||||
EvbLan9668::AddCbs(uint32_t port_id, uint32_t queue_id, DataRate iddle_slope, DataRate port_transmit_rate)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
NS_ASSERT(queue_id < m_queuesPerPort);
|
||||
Ptr<Cbs> cbs = CreateObject<Cbs>();
|
||||
cbs->SetTsnNetDevice(GetPort(port_id));
|
||||
cbs->SetAttribute("IdleSlope", DataRateValue(iddle_slope));
|
||||
cbs->SetAttribute("MaxIdleSlope", DataRateValue(m_maxIddleSlope));
|
||||
cbs->SetAttribute("portTransmitRate", DataRateValue(port_transmit_rate));
|
||||
cbs->SetAttribute("MinLatencyOverhead", TimeValue(m_minCBSLatencyOverhead));
|
||||
cbs->SetAttribute("MaxLatencyOverhead", TimeValue(m_maxCBSLatencyOverhead));
|
||||
|
||||
Ptr<DropTailQueue<Packet>> q = CreateObject<DropTailQueue<Packet>>();
|
||||
q->SetAttribute("MaxSize", QueueSizeValue(m_fifoSize));
|
||||
|
||||
GetPort(port_id)->UpdateQueue(queue_id, q, cbs);
|
||||
}
|
||||
|
||||
void
|
||||
EvbLan9668::AddGclEntry(uint32_t port_id, Time interval, uint8_t state)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
GetPort(port_id)->AddGclEntry(interval, state);
|
||||
}
|
||||
|
||||
void
|
||||
EvbLan9668::StartTas()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
for (int i = 0; i < (int)m_net_devices.size(); i++){
|
||||
m_net_devices[i]->StartTas();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EvbLan9668::AddNullStreamIdentificationFunction(
|
||||
uint32_t streamHandle,
|
||||
Ptr<NullStreamIdentificationFunction> streamIdentificationFunction,
|
||||
std::vector<uint32_t> outFacInputPortIds,
|
||||
std::vector<uint32_t> inFacInputPortIds,
|
||||
std::vector<uint32_t> inFacOutputPortIds,
|
||||
std::vector<uint32_t> outFacOutputPortIds)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
|
||||
std::vector<Ptr<TsnNetDevice>> outFacInputPortList = {};
|
||||
for (int i = 0; i < (int)outFacInputPortIds.size(); i++){
|
||||
outFacInputPortList.insert(outFacInputPortList.end(), GetPort(outFacInputPortIds[i]));
|
||||
}
|
||||
|
||||
std::vector<Ptr<TsnNetDevice>> inFacInputPortList = {};
|
||||
for (int i = 0; i < (int)inFacInputPortIds.size(); i++){
|
||||
inFacInputPortList.insert(inFacInputPortList.end(), GetPort(inFacInputPortIds[i]));
|
||||
}
|
||||
|
||||
std::vector<Ptr<TsnNetDevice>> inFacOutputPortList = {};
|
||||
for (int i = 0; i < (int)inFacOutputPortIds.size(); i++){
|
||||
inFacOutputPortList.insert(inFacOutputPortList.end(), GetPort(inFacOutputPortIds[i]));
|
||||
}
|
||||
|
||||
std::vector<Ptr<TsnNetDevice>> outFacOutputPortList = {};
|
||||
for (int i = 0; i < (int)outFacOutputPortIds.size(); i++){
|
||||
outFacOutputPortList.insert(outFacOutputPortList.end(), GetPort(outFacOutputPortIds[i]));
|
||||
}
|
||||
|
||||
streamIdentificationFunction->SetAttribute("MinLatencyOverhead", TimeValue(m_minNullSIDLatencyOverhead));
|
||||
streamIdentificationFunction->SetAttribute("MaxLatencyOverhead", TimeValue(m_maxNullSIDLatencyOverhead));
|
||||
|
||||
m_node->AddStreamIdentificationFunction(
|
||||
streamHandle,
|
||||
streamIdentificationFunction,
|
||||
outFacInputPortList,
|
||||
inFacInputPortList,
|
||||
inFacOutputPortList,
|
||||
outFacOutputPortList);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
EvbLan9668::AddStreamFilter(Ptr<StreamFilterInstance> streamFilterInstance)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
m_node->AddStreamFilter(streamFilterInstance);
|
||||
}
|
||||
|
||||
uint16_t
|
||||
EvbLan9668::AddFlowMeter(Ptr<FlowMeterInstance> flowMeterInstance)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
return m_node->AddFlowMeter(flowMeterInstance);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
EvbLan9668::AddSequenceGenerationFunction(Ptr<SequenceGenerationFunction> entry)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
m_node->AddSequenceGenerationFunction(entry);
|
||||
}
|
||||
|
||||
void
|
||||
EvbLan9668::AddSequenceRecoveryFunction(Ptr<SequenceRecoveryFunction> rcvy, Ptr<BaseRecoveryFunction> algo, Ptr<LatentErrorDetectionFunction> lat, std::vector<uint32_t> port_ids)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
rcvy->SetAttribute("MinLatencyOverhead", TimeValue(m_minFrerRcvyLatencyOverhead));
|
||||
rcvy->SetAttribute("MaxLatencyOverhead", TimeValue(m_maxFrerRcvyLatencyOverhead));
|
||||
|
||||
algo->SetAttribute("MinResetTimer", TimeValue(m_minFrerSeqRcvyResetDuration));
|
||||
algo->SetAttribute("MaxResetTimer", TimeValue(m_maxFrerSeqRcvyResetDuration));
|
||||
|
||||
lat->SetAttribute("MinTestTimer", TimeValue(m_minFrerLatErrorTestDuration));
|
||||
lat->SetAttribute("MaxTestTimer", TimeValue(m_maxFrerLatErrorTestDuration));
|
||||
lat->SetAttribute("MinResetTimer", TimeValue(m_minFrerLatErrorResetDuration));
|
||||
lat->SetAttribute("MaxResetTimer", TimeValue(m_maxFrerLatErrorResetDuration));
|
||||
|
||||
std::vector<Ptr<TsnNetDevice>> ports = {};
|
||||
for (int i = 0; i < (int)port_ids.size(); i++){
|
||||
ports.insert(ports.end(), GetPort(port_ids[i]));
|
||||
}
|
||||
|
||||
rcvy->SetPorts(ports);
|
||||
rcvy->SetRecoveryFunction(algo);
|
||||
lat->SetRecoveryFunction(algo);
|
||||
rcvy->SetLatentErrorDetectionFunction(lat);
|
||||
|
||||
m_node->AddSequenceRecoveryFunction(rcvy);
|
||||
}
|
||||
|
||||
void
|
||||
EvbLan9668::AddSequenceEncodeDecodeFunction(Ptr<SequenceEncodeDecodeFunction> entry, uint32_t port_id)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
entry->SetPort(GetPort(port_id));
|
||||
m_node->AddSequenceEncodeDecodeFunction(entry);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
220
contrib/real-device/model/evb-lan9668.h
Normal file
220
contrib/real-device/model/evb-lan9668.h
Normal file
@@ -0,0 +1,220 @@
|
||||
#ifndef EVB_LAN9668_H
|
||||
#define EVB_LAN9668_H
|
||||
|
||||
#include "ns3/object.h"
|
||||
|
||||
#include "ns3/tsn-node.h"
|
||||
#include "ns3/tsn-net-device.h"
|
||||
#include "ns3/stream-identification-function-null.h"
|
||||
|
||||
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
/**
|
||||
* \ingroup real-device
|
||||
*
|
||||
* \brief A object to simulate EVB-LAN9668 switch.
|
||||
*/
|
||||
class EvbLan9668: public Object
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* \brief Get the TypeId
|
||||
*
|
||||
* \return The TypeId for this class
|
||||
*/
|
||||
static TypeId GetTypeId();
|
||||
|
||||
/**
|
||||
* \brief Create a EvbLan9668
|
||||
*/
|
||||
EvbLan9668();
|
||||
|
||||
/**
|
||||
* \brief Create a EvbLan9668
|
||||
*/
|
||||
EvbLan9668(std::string name);
|
||||
|
||||
/**
|
||||
* Destroy a EvbLan9668
|
||||
*
|
||||
* This is the destructor for the TsnNode.
|
||||
*/
|
||||
~EvbLan9668();
|
||||
|
||||
// Delete copy constructor and assignment operator to avoid misuse
|
||||
EvbLan9668& operator=(const EvbLan9668&) = delete;
|
||||
EvbLan9668(const EvbLan9668&) = delete;
|
||||
|
||||
/**
|
||||
* \brief Set most of the hardware limits
|
||||
*/
|
||||
void SetHardwareLimits();
|
||||
|
||||
/**
|
||||
* \brief Get a TsnNetDevice from its port id
|
||||
* \param id the port id
|
||||
* \return The TsnNetDevice
|
||||
*/
|
||||
Ptr<TsnNetDevice> GetPort(int id);
|
||||
|
||||
/**
|
||||
* \brief Add a entry in the forwarding database
|
||||
* \param dest the mac address destination
|
||||
* \param vlan_id the vlan id
|
||||
* \param output_port_ids a vector of output port id
|
||||
*/
|
||||
void AddForwardingTableEntry(
|
||||
Mac48Address dest,
|
||||
uint16_t vlan_id,
|
||||
std::vector<uint32_t> output_port_ids);
|
||||
|
||||
/**
|
||||
* \brief Set the datarate of a port
|
||||
* \param id the port id
|
||||
* \param d the datarate
|
||||
*/
|
||||
void SetPortDatarate(int id, DataRate d);
|
||||
|
||||
/**
|
||||
* \brief Add a CBS instance to a port and queue
|
||||
* \para the port id
|
||||
* \param the queue id
|
||||
* \param the iddle_slope
|
||||
* \param the port_transmit_rate
|
||||
*/
|
||||
void AddCbs(uint32_t port_id, uint32_t queue_id, DataRate iddle_slope, DataRate port_transmit_rate);
|
||||
|
||||
/**
|
||||
* \brief Add a GCL entry to a port
|
||||
* \para the port id
|
||||
* \param the GCL entry duration
|
||||
* \param the GCL entry state
|
||||
*/
|
||||
void AddGclEntry(uint32_t port_id, Time interval, uint8_t state);
|
||||
|
||||
/**
|
||||
* \brief Start TAS operation
|
||||
*/
|
||||
void StartTas();
|
||||
|
||||
/**
|
||||
* \brief Add a null stream identification function
|
||||
* \para streamHandle
|
||||
* \param stream Identification Function
|
||||
* \param out-facing input port ids
|
||||
* \param in-facing input port ids
|
||||
* \param in-facing output port ids
|
||||
* \param out-facing output port ids
|
||||
*/
|
||||
void
|
||||
AddNullStreamIdentificationFunction(
|
||||
uint32_t streamHandle,
|
||||
Ptr<NullStreamIdentificationFunction> streamIdentificationFunction,
|
||||
std::vector<uint32_t> outFacInputPortIds,
|
||||
std::vector<uint32_t> inFacInputPortIds,
|
||||
std::vector<uint32_t> inFacOutputPortIds,
|
||||
std::vector<uint32_t> outFacOutputPortIds);
|
||||
|
||||
|
||||
/**
|
||||
* \brief Add a stream filter to the node
|
||||
* \param the stream filter instance
|
||||
*/
|
||||
void
|
||||
AddStreamFilter(Ptr<StreamFilterInstance> streamFilterInstance);
|
||||
|
||||
/**
|
||||
* \brief Add a flow meter to the node
|
||||
* \param the flow meter instance
|
||||
*/
|
||||
uint16_t
|
||||
AddFlowMeter(Ptr<FlowMeterInstance> flowMeterInstance);
|
||||
|
||||
/**
|
||||
* \brief Add generation function to the node
|
||||
* \param the genertation function
|
||||
*/
|
||||
void
|
||||
AddSequenceGenerationFunction(Ptr<SequenceGenerationFunction> entry);
|
||||
|
||||
/**
|
||||
* \brief Add recovery function to the node
|
||||
* \param the recovery function
|
||||
* \param the recovery algo (match or vector)
|
||||
* \param the latent error detection function
|
||||
* \param the port ids
|
||||
*/
|
||||
void
|
||||
AddSequenceRecoveryFunction(Ptr<SequenceRecoveryFunction> rcvy, Ptr<BaseRecoveryFunction> algo, Ptr<LatentErrorDetectionFunction> lat, std::vector<uint32_t> port_ids);
|
||||
|
||||
/**
|
||||
* \brief Add encode/decode function to the node
|
||||
* \param the encode/decode function
|
||||
* \param the port id
|
||||
*/
|
||||
void
|
||||
AddSequenceEncodeDecodeFunction(Ptr<SequenceEncodeDecodeFunction> entry, uint32_t port_id);
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
Ptr<TsnNode> m_node;
|
||||
std::vector<Ptr<TsnNetDevice>> m_net_devices;
|
||||
Ptr<SwitchNetDevice> m_switch_net_device;
|
||||
|
||||
|
||||
//Hardware limits
|
||||
uint16_t m_portNumber = 8;
|
||||
uint16_t m_queuesPerPort = 8;
|
||||
uint16_t m_maxFdbEntryNumber = 64;
|
||||
QueueSize m_fifoSize = QueueSize("102p");
|
||||
Time m_minForwardingLatency = NanoSeconds(2660); //2660
|
||||
Time m_maxForwardingLatency = NanoSeconds(2370); //2370
|
||||
|
||||
//CBS
|
||||
DataRate m_maxIddleSlope = DataRate("3.282Gb/s");
|
||||
Time m_minCBSLatencyOverhead = NanoSeconds(0); //-25ns
|
||||
Time m_maxCBSLatencyOverhead = NanoSeconds(0); //-9ns
|
||||
|
||||
//Tas
|
||||
uint32_t m_maxGclEntryNumber = 256;
|
||||
Time m_maxGclCycleDuration = NanoSeconds(999999999);
|
||||
Time m_maxGclTimeInterval = NanoSeconds(999999999);
|
||||
Time m_minTASLatencyOverhead = NanoSeconds(0);
|
||||
Time m_maxTASLatencyOverhead = NanoSeconds(0);
|
||||
|
||||
//Stream identification
|
||||
uint32_t m_maxSidEntryNumber = 127;
|
||||
Time m_minNullSIDLatencyOverhead = NanoSeconds(0); //-9ns
|
||||
Time m_maxNullSIDLatencyOverhead = NanoSeconds(0); //-13ns
|
||||
Time m_minSourceMacSIDLatencyOverhead = NanoSeconds(0);
|
||||
Time m_maxSourceMacSIDLatencyOverhead = NanoSeconds(0);
|
||||
|
||||
//PSFP
|
||||
uint32_t m_maxPsfpFilterEntryNumber = 176;
|
||||
uint32_t m_maxPsfpStreamGateEntryNumber = 176;
|
||||
uint32_t m_maxPsfpFlowMeterEntryNumber = 240;
|
||||
|
||||
//FRER
|
||||
uint32_t m_maxFrerSeqGenEntryNumber = 99;
|
||||
uint32_t m_maxFrerSeqRcvyEntryNumber = 99;
|
||||
uint32_t m_maxFrerSeqEncEntryNumber = 99;
|
||||
Time m_minFrerSeqRcvyResetDuration = MilliSeconds(1);
|
||||
Time m_maxFrerSeqRcvyResetDuration = Seconds(4.095);
|
||||
Time m_minFrerLatErrorTestDuration = Seconds(1);
|
||||
Time m_maxFrerLatErrorTestDuration = Seconds(86400);
|
||||
Time m_minFrerLatErrorResetDuration = Seconds(1);
|
||||
Time m_maxFrerLatErrorResetDuration = Seconds(86400);
|
||||
Time m_minFrerRcvyLatencyOverhead = NanoSeconds(40); //40ns
|
||||
Time m_maxFrerRcvyLatencyOverhead = NanoSeconds(40); //40ns
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* EVB_LAN9668_H */
|
||||
23
contrib/real-device/test/examples-to-run.py
Normal file
23
contrib/real-device/test/examples-to-run.py
Normal file
@@ -0,0 +1,23 @@
|
||||
#! /usr/bin/env python3
|
||||
|
||||
# A list of C++ examples to run in order to ensure that they remain
|
||||
# buildable and runnable over time. Each tuple in the list contains
|
||||
#
|
||||
# (example_name, do_run, do_valgrind_run).
|
||||
#
|
||||
# See test.py for more information.
|
||||
cpp_examples = [
|
||||
("evb-lan9668-sp", "True", "True"),
|
||||
("evb-lan9668-cbs", "True", "True"),
|
||||
("evb-lan9668-tas", "True", "True"),
|
||||
("evb-lan9668-psfp", "True", "True"),
|
||||
("evb-lan9668-frer", "True", "True"),
|
||||
]
|
||||
|
||||
# A list of Python examples to run in order to ensure that they remain
|
||||
# runnable over time. Each tuple in the list contains
|
||||
#
|
||||
# (example_name, do_run).
|
||||
#
|
||||
# See test.py for more information.
|
||||
python_examples = []
|
||||
86
contrib/real-device/test/real-device-test-suite.cc
Normal file
86
contrib/real-device/test/real-device-test-suite.cc
Normal file
@@ -0,0 +1,86 @@
|
||||
|
||||
// Include a header file from your module to test.
|
||||
#include "ns3/evb-lan9668.h"
|
||||
|
||||
// An essential include is test.h
|
||||
#include "ns3/test.h"
|
||||
|
||||
// Do not put your test classes in namespace ns3. You may find it useful
|
||||
// to use the using directive to access the ns3 namespace directly
|
||||
using namespace ns3;
|
||||
|
||||
// Add a doxygen group for tests.
|
||||
// If you have more than one test, this should be in only one of them.
|
||||
/**
|
||||
* \defgroup real-device-tests Tests for real-device
|
||||
* \ingroup real-device
|
||||
* \ingroup tests
|
||||
*/
|
||||
|
||||
// This is an example TestCase.
|
||||
/**
|
||||
* \ingroup real-device-tests
|
||||
* Test case for feature 1
|
||||
*/
|
||||
class RealDeviceTestCase1 : public TestCase
|
||||
{
|
||||
public:
|
||||
RealDeviceTestCase1();
|
||||
virtual ~RealDeviceTestCase1();
|
||||
|
||||
private:
|
||||
void DoRun() override;
|
||||
};
|
||||
|
||||
// Add some help text to this case to describe what it is intended to test
|
||||
RealDeviceTestCase1::RealDeviceTestCase1()
|
||||
: TestCase("RealDevice test case (does nothing)")
|
||||
{
|
||||
}
|
||||
|
||||
// This destructor does nothing but we include it as a reminder that
|
||||
// the test case should clean up after itself
|
||||
RealDeviceTestCase1::~RealDeviceTestCase1()
|
||||
{
|
||||
}
|
||||
|
||||
//
|
||||
// This method is the pure virtual method from class TestCase that every
|
||||
// TestCase must implement
|
||||
//
|
||||
void
|
||||
RealDeviceTestCase1::DoRun()
|
||||
{
|
||||
// A wide variety of test macros are available in src/core/test.h
|
||||
NS_TEST_ASSERT_MSG_EQ(true, true, "true doesn't equal true for some reason");
|
||||
// Use this one for floating point comparisons
|
||||
NS_TEST_ASSERT_MSG_EQ_TOL(0.01, 0.01, 0.001, "Numbers are not equal within tolerance");
|
||||
}
|
||||
|
||||
// The TestSuite class names the TestSuite, identifies what type of TestSuite,
|
||||
// and enables the TestCases to be run. Typically, only the constructor for
|
||||
// this class must be defined
|
||||
|
||||
/**
|
||||
* \ingroup real-device-tests
|
||||
* TestSuite for module real-device
|
||||
*/
|
||||
class RealDeviceTestSuite : public TestSuite
|
||||
{
|
||||
public:
|
||||
RealDeviceTestSuite();
|
||||
};
|
||||
|
||||
RealDeviceTestSuite::RealDeviceTestSuite()
|
||||
: TestSuite("real-device", UNIT)
|
||||
{
|
||||
// TestDuration for TestCase can be QUICK, EXTENSIVE or TAKES_FOREVER
|
||||
AddTestCase(new RealDeviceTestCase1, TestCase::QUICK);
|
||||
}
|
||||
|
||||
// Do not forget to allocate an instance of this TestSuite
|
||||
/**
|
||||
* \ingroup real-device-tests
|
||||
* Static variable for test initialization
|
||||
*/
|
||||
static RealDeviceTestSuite srealDeviceTestSuite;
|
||||
24
contrib/trace/CMakeLists.txt
Normal file
24
contrib/trace/CMakeLists.txt
Normal file
@@ -0,0 +1,24 @@
|
||||
check_include_file_cxx(stdint.h HAVE_STDINT_H)
|
||||
if(HAVE_STDINT_H)
|
||||
add_definitions(-DHAVE_STDINT_H)
|
||||
endif()
|
||||
|
||||
set(examples_as_tests_sources)
|
||||
if(${ENABLE_EXAMPLES})
|
||||
set(examples_as_tests_sources
|
||||
#test/trace-examples-test-suite.cc
|
||||
)
|
||||
endif()
|
||||
|
||||
build_lib(
|
||||
LIBNAME trace
|
||||
SOURCE_FILES model/animation-trace.cc
|
||||
model/gantt-trace.cc
|
||||
HEADER_FILES model/animation-trace.h
|
||||
model/gantt-trace.h
|
||||
LIBRARIES_TO_LINK ${libcore}
|
||||
${libethernet}
|
||||
${libtsn}
|
||||
TEST_SOURCES test/trace-test-suite.cc
|
||||
${examples_as_tests_sources}
|
||||
)
|
||||
19
contrib/trace/examples/CMakeLists.txt
Normal file
19
contrib/trace/examples/CMakeLists.txt
Normal file
@@ -0,0 +1,19 @@
|
||||
set(base_examples
|
||||
tsn-point2point-netanim
|
||||
tsn-switched-withFRER-netanim
|
||||
)
|
||||
foreach(
|
||||
example
|
||||
${base_examples}
|
||||
)
|
||||
build_lib_example(
|
||||
NAME ${example}
|
||||
SOURCE_FILES ${example}.cc
|
||||
LIBRARIES_TO_LINK ${libtrace}
|
||||
${libcore}
|
||||
${libnetwork}
|
||||
${libethernet}
|
||||
${libtraffic-generator}
|
||||
${libtsn}
|
||||
)
|
||||
endforeach()
|
||||
102
contrib/trace/examples/tsn-point2point-netanim.cc
Normal file
102
contrib/trace/examples/tsn-point2point-netanim.cc
Normal file
@@ -0,0 +1,102 @@
|
||||
#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/animation-trace.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. This example generate a NetAnim trace for graphical purpose.
|
||||
* 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);
|
||||
LogComponentEnable("AnimationTrace", LOG_LEVEL_ALL);
|
||||
|
||||
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));
|
||||
|
||||
//NetAnim
|
||||
// Create the animation trace object and configure for specified output
|
||||
AnimationTrace anim = AnimationTrace("example-animation.xml");
|
||||
anim.SetNodePosition(n1, 10, 0);
|
||||
anim.StartAnimation();
|
||||
Packet::EnablePrinting(); //Need to enable packet printing for metadata display on NetAnim
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(Seconds(10));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
315
contrib/trace/examples/tsn-switched-withFRER-netanim.cc
Normal file
315
contrib/trace/examples/tsn-switched-withFRER-netanim.cc
Normal file
@@ -0,0 +1,315 @@
|
||||
#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/animation-trace.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 ==== /
|
||||
*
|
||||
* This example generate a NetAnim trace for graphical purpose.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
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> 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>();
|
||||
net0->Attach(l0);
|
||||
net2_1->Attach(l0);
|
||||
Ptr<EthernetChannel> l1 = CreateObject<EthernetChannel>();
|
||||
net2_2->Attach(l1);
|
||||
net3_1->Attach(l1);
|
||||
Ptr<EthernetChannel> l2 = CreateObject<EthernetChannel>();
|
||||
net2_3->Attach(l2);
|
||||
net4_1->Attach(l2);
|
||||
Ptr<EthernetChannel> l3 = CreateObject<EthernetChannel>();
|
||||
net3_2->Attach(l3);
|
||||
net5_1->Attach(l3);
|
||||
Ptr<EthernetChannel> l4 = CreateObject<EthernetChannel>();
|
||||
net4_2->Attach(l4);
|
||||
net5_2->Attach(l4);
|
||||
Ptr<EthernetChannel> l5 = CreateObject<EthernetChannel>();
|
||||
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)));
|
||||
|
||||
//NetAnim
|
||||
// Create the animation trace object and configure for specified output
|
||||
AnimationTrace anim = AnimationTrace("example-animation.xml");
|
||||
anim.SetNodePosition(n0, 0, 0);
|
||||
anim.SetNodePosition(n1, 40, 0);
|
||||
anim.SetNodePosition(n2, 10, 0);
|
||||
anim.SetNodePosition(n3, 20, -10);
|
||||
anim.SetNodePosition(n4, 20, 10);
|
||||
anim.SetNodePosition(n5, 30, 0);
|
||||
anim.StartAnimation();
|
||||
Packet::EnablePrinting(); //Need to enable packet printing for metadata display on NetAnim
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(MilliSeconds(50));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
500
contrib/trace/model/animation-trace.cc
Normal file
500
contrib/trace/model/animation-trace.cc
Normal file
@@ -0,0 +1,500 @@
|
||||
#include "animation-trace.h"
|
||||
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/config.h"
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/mac48-address.h"
|
||||
#include "ns3/net-device.h"
|
||||
#include "ns3/channel.h"
|
||||
#include "ns3/node-container.h"
|
||||
#include "ns3/node-list.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/nstime.h"
|
||||
#include "ns3/ptr.h"
|
||||
#include "ns3/simulator.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("AnimationTrace");
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED(AnimationTrace);
|
||||
|
||||
|
||||
AnimationTrace::AnimationTrace(std::string filename)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
m_outputFileName = filename;
|
||||
}
|
||||
|
||||
|
||||
AnimationTrace::~AnimationTrace()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
StopAnimation();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AnimationTrace::StartAnimation()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
m_currentPktCount = 0;
|
||||
SetOutputFile(m_outputFileName);
|
||||
WriteXmlAnim();
|
||||
WriteNodes();
|
||||
WriteNodeColors();
|
||||
WriteNodeSizes();
|
||||
WriteNodeDescription();
|
||||
WriteLinkProperties();
|
||||
ConnectCallbacks();
|
||||
}
|
||||
|
||||
void
|
||||
AnimationTrace::StopAnimation()
|
||||
{
|
||||
NS_LOG_INFO("Stopping Animation");
|
||||
if (m_f)
|
||||
{
|
||||
// Terminate the anim element
|
||||
WriteXmlClose("anim");
|
||||
std::fclose(m_f);
|
||||
m_f = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AnimationTrace::SetNodePosition(Ptr<Node> n, int x, int y)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
m_nodeLocation[n->GetId()] = {x,y};
|
||||
}
|
||||
|
||||
void
|
||||
AnimationTrace::SetOutputFile(const std::string& fn)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
FILE* f = nullptr;
|
||||
f = std::fopen(fn.c_str(), "w");
|
||||
if (!f)
|
||||
{
|
||||
NS_FATAL_ERROR("Unable to open output file:" << fn);
|
||||
return; // Can't open output file
|
||||
}
|
||||
m_f = f;
|
||||
}
|
||||
|
||||
void
|
||||
AnimationTrace::WriteXmlAnim()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
AnimXmlElement element("anim");
|
||||
element.AddAttribute("ver", m_version);
|
||||
FILE* f = m_f;
|
||||
element.AddAttribute("filetype", "animation");
|
||||
WriteN(element.ToString(false) + ">\n", f);
|
||||
}
|
||||
|
||||
void
|
||||
AnimationTrace::WriteXmlClose(std::string name)
|
||||
{
|
||||
std::string closeString = "</" + name + ">\n";
|
||||
WriteN(closeString, m_f);
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
AnimationTrace::WriteNodes()
|
||||
{
|
||||
for (auto i = NodeList::Begin(); i != NodeList::End(); ++i)
|
||||
{
|
||||
Ptr<Node> n = *i;
|
||||
NS_LOG_INFO("Update Position for Node: " << n->GetId());
|
||||
std::vector<int> pos = {0,0};
|
||||
if (m_nodeLocation.count(n->GetId()) > 0)
|
||||
{
|
||||
pos = m_nodeLocation[n->GetId()];
|
||||
}
|
||||
WriteXmlNode(n->GetId(), n->GetSystemId(), pos[0], pos[1]);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AnimationTrace::WriteXmlNode(uint32_t id, uint32_t sysId, double locX, double locY)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
AnimXmlElement element("node");
|
||||
element.AddAttribute("id", id);
|
||||
element.AddAttribute("sysId", sysId);
|
||||
element.AddAttribute("locX", locX);
|
||||
element.AddAttribute("locY", locY);
|
||||
WriteN(element.ToString(), m_f);
|
||||
}
|
||||
|
||||
void
|
||||
AnimationTrace::WriteNodeColors()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
for (auto i = NodeList::Begin(); i != NodeList::End(); ++i)
|
||||
{
|
||||
Ptr<Node> n = *i;
|
||||
WriteXmlNodeColors(n->GetId(), 255, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AnimationTrace::WriteXmlNodeColors(uint32_t nodeId, uint8_t r, uint8_t g, uint8_t b)
|
||||
{
|
||||
NS_ASSERT(NodeList::GetNode(nodeId));
|
||||
NS_LOG_INFO("Setting node color for Node Id:" << nodeId);
|
||||
|
||||
AnimXmlElement element("nu");
|
||||
element.AddAttribute("p", "c");
|
||||
element.AddAttribute("t", Simulator::Now().GetSeconds());
|
||||
element.AddAttribute("id", nodeId);
|
||||
element.AddAttribute("r", (uint32_t)r);
|
||||
element.AddAttribute("g", (uint32_t)g);
|
||||
element.AddAttribute("b", (uint32_t)b);
|
||||
WriteN(element.ToString(), m_f);
|
||||
}
|
||||
|
||||
void
|
||||
AnimationTrace::WriteNodeSizes()
|
||||
{
|
||||
for (auto i = NodeList::Begin(); i != NodeList::End(); ++i)
|
||||
{
|
||||
Ptr<Node> n = *i;
|
||||
NS_LOG_INFO("Update Size for Node: " << n->GetId());
|
||||
WriteXmlUpdateNodeSize(n->GetId(), .5, .5);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AnimationTrace::WriteXmlUpdateNodeSize(uint32_t nodeId, double width, double height)
|
||||
{
|
||||
AnimXmlElement element("nu");
|
||||
element.AddAttribute("p", "s");
|
||||
element.AddAttribute("t", Simulator::Now().GetSeconds());
|
||||
element.AddAttribute("id", nodeId);
|
||||
element.AddAttribute("w", width);
|
||||
element.AddAttribute("h", height);
|
||||
WriteN(element.ToString(), m_f);
|
||||
}
|
||||
|
||||
void
|
||||
AnimationTrace::WriteNodeDescription()
|
||||
{
|
||||
for (auto i = NodeList::Begin(); i != NodeList::End(); ++i)
|
||||
{
|
||||
Ptr<Node> n = *i;
|
||||
NS_LOG_INFO("Update Description for Node: " << n->GetId());
|
||||
WriteXmlUpdateNodeDescription(n);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AnimationTrace::WriteXmlUpdateNodeDescription(Ptr<Node> n)
|
||||
{
|
||||
AnimXmlElement element("nu");
|
||||
element.AddAttribute("p", "d");
|
||||
element.AddAttribute("t", Simulator::Now().GetSeconds());
|
||||
element.AddAttribute("id", n->GetId());
|
||||
std::string name = Names::FindName(n);
|
||||
if (name != "")
|
||||
{
|
||||
element.AddAttribute("descr", name, true);
|
||||
WriteN(element.ToString(), m_f);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
AnimationTrace::WriteLinkProperties()
|
||||
{
|
||||
for (auto i = NodeList::Begin(); i != NodeList::End(); ++i)
|
||||
{
|
||||
Ptr<Node> n = *i;
|
||||
uint32_t n1Id = n->GetId();
|
||||
uint32_t nDev = n->GetNDevices(); // Number of devices
|
||||
for (uint32_t i = 0; i < nDev; ++i)
|
||||
{
|
||||
Ptr<NetDevice> dev = n->GetDevice(i);
|
||||
NS_ASSERT(dev);
|
||||
Ptr<Channel> ch = dev->GetChannel();
|
||||
std::string channelType = "Unknown channel";
|
||||
if (ch)
|
||||
{
|
||||
channelType = ch->GetInstanceTypeId().GetName();
|
||||
}
|
||||
NS_LOG_DEBUG("Got ChannelType" << channelType);
|
||||
|
||||
if (channelType == "ns3::EthernetChannel")
|
||||
{ // Since these are duplex links, we only need to dump
|
||||
// if srcid < dstid
|
||||
std::size_t nChDev = ch->GetNDevices();
|
||||
for (std::size_t j = 0; j < nChDev; ++j)
|
||||
{
|
||||
Ptr<NetDevice> chDev = ch->GetDevice(j);
|
||||
uint32_t n2Id = chDev->GetNode()->GetId();
|
||||
if (n1Id < n2Id)
|
||||
{
|
||||
WriteXmlLink(n1Id, 0, n2Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_LOG_INFO("Unknown channel type : " << channelType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AnimationTrace::WriteXmlLink(uint32_t fromId, uint32_t toLp, uint32_t toId)
|
||||
{
|
||||
AnimXmlElement element("link");
|
||||
element.AddAttribute("fromId", fromId);
|
||||
element.AddAttribute("toId", toId);
|
||||
element.AddAttribute("fd", "", true); ///< from node description
|
||||
element.AddAttribute("td", "", true); ///< to node description
|
||||
element.AddAttribute("ld", "", true); ///< link description
|
||||
WriteN(element.ToString(), m_f);
|
||||
}
|
||||
|
||||
void
|
||||
AnimationTrace::WriteXmlP(std::string pktType,
|
||||
uint32_t fId,
|
||||
double fbTx,
|
||||
double lbTx,
|
||||
uint32_t tId,
|
||||
double fbRx,
|
||||
double lbRx,
|
||||
std::string metaInfo)
|
||||
{
|
||||
AnimXmlElement element(pktType);
|
||||
element.AddAttribute("fId", fId);
|
||||
element.AddAttribute("fbTx", fbTx);
|
||||
element.AddAttribute("lbTx", lbTx);
|
||||
if (!metaInfo.empty())
|
||||
{
|
||||
element.AddAttribute("meta-info", metaInfo.c_str(), true);
|
||||
}
|
||||
element.AddAttribute("tId", tId);
|
||||
element.AddAttribute("fbRx", fbRx);
|
||||
element.AddAttribute("lbRx", lbRx);
|
||||
WriteN(element.ToString(), m_f);
|
||||
}
|
||||
|
||||
void
|
||||
AnimationTrace::ConnectCallbacks()
|
||||
{
|
||||
// Connect the callbacks
|
||||
Config::ConnectFailSafe("/ChannelList/*/TxRxEthernet",
|
||||
MakeCallback(&AnimationTrace::DevTxTrace, this));
|
||||
}
|
||||
|
||||
void
|
||||
AnimationTrace::DevTxTrace(std::string context,
|
||||
Ptr<const Packet> p,
|
||||
Ptr<NetDevice> tx,
|
||||
Ptr<NetDevice> rx,
|
||||
Time txTime,
|
||||
Time rxTime)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
NS_ASSERT(tx);
|
||||
NS_ASSERT(rx);
|
||||
Time now = Simulator::Now();
|
||||
double fbTx = now.GetSeconds();
|
||||
double lbTx = (now + txTime).GetSeconds();
|
||||
double fbRx = (now + rxTime - txTime).GetSeconds();
|
||||
double lbRx = (now + rxTime).GetSeconds();
|
||||
if(CheckMaxPktsPerTraceFile())
|
||||
{
|
||||
WriteXmlP("p",
|
||||
tx->GetNode()->GetId(),
|
||||
fbTx,
|
||||
lbTx,
|
||||
rx->GetNode()->GetId(),
|
||||
fbRx,
|
||||
lbRx,
|
||||
GetPacketMetadata(p));
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
AnimationTrace::CheckMaxPktsPerTraceFile()
|
||||
{
|
||||
++m_currentPktCount;
|
||||
if (m_currentPktCount <= m_maxPkts)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
NS_LOG_INFO("Max Packets exceeded !");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
AnimationTrace::WriteN(const std::string& st, FILE* f)
|
||||
{
|
||||
if (!f)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return WriteN(st.c_str(), st.length(), f);
|
||||
}
|
||||
|
||||
int
|
||||
AnimationTrace::WriteN(const char* data, uint32_t count, FILE* f)
|
||||
{
|
||||
if (!f)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
// Write count bytes to h from data
|
||||
uint32_t nLeft = count;
|
||||
const char* p = data;
|
||||
uint32_t written = 0;
|
||||
while (nLeft)
|
||||
{
|
||||
int n = std::fwrite(p, 1, nLeft, f);
|
||||
if (n <= 0)
|
||||
{
|
||||
return written;
|
||||
}
|
||||
written += n;
|
||||
nLeft -= n;
|
||||
p += n;
|
||||
}
|
||||
return written;
|
||||
}
|
||||
|
||||
std::string
|
||||
AnimationTrace::GetPacketMetadata(Ptr<const Packet> p)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
std::ostringstream oss;
|
||||
p->Print(oss);
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/***** AnimXmlElement *****/
|
||||
|
||||
AnimationTrace::AnimXmlElement::AnimXmlElement(std::string tagName, bool emptyElement)
|
||||
: m_tagName(tagName),
|
||||
m_text("")
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
AnimationTrace::AnimXmlElement::AddAttribute(std::string attribute, T value, bool xmlEscape)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << std::setprecision(10);
|
||||
oss << value;
|
||||
std::string attributeString = attribute;
|
||||
if (xmlEscape)
|
||||
{
|
||||
attributeString += "=\"";
|
||||
std::string valueStr = oss.str();
|
||||
for (auto it = valueStr.begin(); it != valueStr.end(); ++it)
|
||||
{
|
||||
switch (*it)
|
||||
{
|
||||
case '&':
|
||||
attributeString += "&";
|
||||
break;
|
||||
case '\"':
|
||||
attributeString += """;
|
||||
break;
|
||||
case '\'':
|
||||
attributeString += "'";
|
||||
break;
|
||||
case '<':
|
||||
attributeString += "<";
|
||||
break;
|
||||
case '>':
|
||||
attributeString += ">";
|
||||
break;
|
||||
default:
|
||||
attributeString += *it;
|
||||
break;
|
||||
}
|
||||
}
|
||||
attributeString += "\" ";
|
||||
}
|
||||
else
|
||||
{
|
||||
attributeString += "=\"" + oss.str() + "\" ";
|
||||
}
|
||||
m_attributes.push_back(attributeString);
|
||||
}
|
||||
|
||||
void
|
||||
AnimationTrace::AnimXmlElement::AppendChild(AnimXmlElement e)
|
||||
{
|
||||
m_children.push_back(e.ToString());
|
||||
}
|
||||
|
||||
void
|
||||
AnimationTrace::AnimXmlElement::SetText(std::string text)
|
||||
{
|
||||
m_text = text;
|
||||
}
|
||||
|
||||
std::string
|
||||
AnimationTrace::AnimXmlElement::ToString(bool autoClose)
|
||||
{
|
||||
std::string elementString = "<" + m_tagName + " ";
|
||||
|
||||
for (auto i = m_attributes.begin(); i != m_attributes.end(); ++i)
|
||||
{
|
||||
elementString += *i;
|
||||
}
|
||||
if (m_children.empty() && m_text.empty())
|
||||
{
|
||||
if (autoClose)
|
||||
{
|
||||
elementString += "/>";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
elementString += ">";
|
||||
if (!m_text.empty())
|
||||
{
|
||||
elementString += m_text;
|
||||
}
|
||||
if (!m_children.empty())
|
||||
{
|
||||
elementString += "\n";
|
||||
for (auto i = m_children.begin(); i != m_children.end(); ++i)
|
||||
{
|
||||
elementString += *i + "\n";
|
||||
}
|
||||
}
|
||||
if (autoClose)
|
||||
{
|
||||
elementString += "</" + m_tagName + ">";
|
||||
}
|
||||
}
|
||||
|
||||
return elementString + ((autoClose) ? "\n" : "");
|
||||
}
|
||||
|
||||
}
|
||||
142
contrib/trace/model/animation-trace.h
Normal file
142
contrib/trace/model/animation-trace.h
Normal file
@@ -0,0 +1,142 @@
|
||||
#ifndef ANIMATION_TRACE_H
|
||||
#define ANIMATION_TRACE_H
|
||||
|
||||
#include "ns3/object.h"
|
||||
#include "ns3/config.h"
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/net-device.h"
|
||||
#include "ns3/node-list.h"
|
||||
#include "ns3/nstime.h"
|
||||
#include "ns3/ptr.h"
|
||||
#include "ns3/simulator.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
|
||||
// Add a doxygen group for this module.
|
||||
// If you have more than one file, this should be in only one of them.
|
||||
/**
|
||||
* \defgroup animation-trace Description of the animation-trace
|
||||
*/
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
class AnimationTrace : public Object
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \brief Constructor
|
||||
* \param filename The Filename for the trace file used by the Animator
|
||||
*
|
||||
*/
|
||||
AnimationTrace(const std::string filename);
|
||||
|
||||
/**
|
||||
* \brief Destructor for the animator interface.
|
||||
*
|
||||
*/
|
||||
~AnimationTrace();
|
||||
|
||||
|
||||
void StartAnimation();
|
||||
void StopAnimation();
|
||||
|
||||
void SetNodePosition(Ptr<Node> n, int x, int y);
|
||||
|
||||
|
||||
/// AnimXmlElement class
|
||||
class AnimXmlElement
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param tagName tag name
|
||||
* \param emptyElement empty element?
|
||||
*/
|
||||
AnimXmlElement(std::string tagName, bool emptyElement = true);
|
||||
template <typename T>
|
||||
/**
|
||||
* Add attribute function
|
||||
* \param attribute the attribute name
|
||||
* \param value the attribute value
|
||||
* \param xmlEscape true to escape
|
||||
*/
|
||||
void AddAttribute(std::string attribute, T value, bool xmlEscape = false);
|
||||
/**
|
||||
* Set text function
|
||||
* \param text the text for the element
|
||||
*/
|
||||
void SetText(std::string text);
|
||||
/**
|
||||
* Append child function
|
||||
* \param e the element to add as a child
|
||||
*/
|
||||
void AppendChild(AnimXmlElement e);
|
||||
/**
|
||||
* Get text for the element function
|
||||
* \param autoClose auto close the element
|
||||
* \returns the text
|
||||
*/
|
||||
std::string ToString(bool autoClose = true);
|
||||
|
||||
private:
|
||||
std::string m_tagName; ///< tag name
|
||||
std::string m_text; ///< element string
|
||||
std::vector<std::string> m_attributes; ///< list of attributes
|
||||
std::vector<std::string> m_children; ///< list of children
|
||||
};
|
||||
|
||||
private:
|
||||
void SetOutputFile(const std::string& fn);
|
||||
|
||||
void WriteNodes();
|
||||
void WriteNodeColors();
|
||||
void WriteNodeSizes();
|
||||
void WriteNodeDescription();
|
||||
void WriteLinkProperties();
|
||||
|
||||
|
||||
void WriteXmlAnim();
|
||||
void WriteXmlClose(std::string name);
|
||||
void WriteXmlNode(uint32_t id, uint32_t sysId, double locX, double locY);
|
||||
void WriteXmlNodeColors(uint32_t nodeId, uint8_t r, uint8_t g, uint8_t b);
|
||||
void WriteXmlUpdateNodeSize(uint32_t nodeId, double width, double height);
|
||||
void WriteXmlUpdateNodeDescription(Ptr<Node> n);
|
||||
void WriteXmlLink(uint32_t fromId, uint32_t toLp, uint32_t toId);
|
||||
void WriteXmlP(std::string pktType,
|
||||
uint32_t fId,
|
||||
double fbTx,
|
||||
double lbTx,
|
||||
uint32_t tId,
|
||||
double fbRx,
|
||||
double lbRx,
|
||||
std::string metaInfo = "");
|
||||
|
||||
void ConnectCallbacks();
|
||||
void DevTxTrace(std::string context,
|
||||
Ptr<const Packet> p,
|
||||
Ptr<NetDevice> tx,
|
||||
Ptr<NetDevice> rx,
|
||||
Time txTime,
|
||||
Time rxTime);
|
||||
bool CheckMaxPktsPerTraceFile();
|
||||
|
||||
int WriteN(const std::string& st, FILE* f);
|
||||
int WriteN(const char* data, uint32_t count, FILE* f);
|
||||
std::string GetPacketMetadata(Ptr<const Packet> p);
|
||||
|
||||
std::string m_version = "netanim-3.109";
|
||||
std::string m_outputFileName;
|
||||
uint64_t m_currentPktCount = 0;
|
||||
uint64_t m_maxPkts = 10000;
|
||||
FILE* m_f;
|
||||
uint64_t gAnimUid; ///< Packet unique identifier used by AnimationInterface
|
||||
|
||||
std::map<uint32_t, std::vector<int>> m_nodeLocation; ///< node location
|
||||
std::map<uint32_t, std::string> m_nodeDescription;
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* ANIMATION_TRACE_H */
|
||||
231
contrib/trace/model/gantt-trace.cc
Normal file
231
contrib/trace/model/gantt-trace.cc
Normal file
@@ -0,0 +1,231 @@
|
||||
#include "gantt-trace.h"
|
||||
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/config.h"
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/mac48-address.h"
|
||||
#include "ns3/net-device.h"
|
||||
#include "ns3/channel.h"
|
||||
#include "ns3/node-container.h"
|
||||
#include "ns3/node-list.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/nstime.h"
|
||||
#include "ns3/ptr.h"
|
||||
#include "ns3/simulator.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
|
||||
#include "ns3/ethernet-header2.h"
|
||||
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("GanttTrace");
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED(GanttTrace);
|
||||
|
||||
|
||||
GanttTrace::GanttTrace(std::string filename)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
m_outputFileName = filename;
|
||||
m_f = nullptr;
|
||||
}
|
||||
|
||||
|
||||
GanttTrace::~GanttTrace()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
StopGantt();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
GanttTrace::StartGantt()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
SetOutputFile(m_outputFileName);
|
||||
ConnectCallbacks();
|
||||
}
|
||||
|
||||
void
|
||||
GanttTrace::StopGantt()
|
||||
{
|
||||
NS_LOG_INFO("Stopping Gantt");
|
||||
if (m_f)
|
||||
{
|
||||
// Terminate the anim element
|
||||
std::fclose(m_f);
|
||||
m_f = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GanttTrace::SetOutputFile(const std::string& fn)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
FILE* f = nullptr;
|
||||
f = std::fopen(fn.c_str(), "w");
|
||||
if (!f)
|
||||
{
|
||||
NS_FATAL_ERROR("Unable to open output file:" << fn);
|
||||
return; // Can't open output file
|
||||
}
|
||||
m_f = f;
|
||||
NS_ASSERT(m_f);
|
||||
}
|
||||
|
||||
void
|
||||
GanttTrace::ConnectCallbacks()
|
||||
{
|
||||
// Connect the callbacks
|
||||
Config::ConnectFailSafe("/ChannelList/*/TxRxEthernet",
|
||||
MakeCallback(&GanttTrace::DevTxTrace, this));
|
||||
|
||||
Config::ConnectFailSafe("/NodeList/*/DeviceList/*/MacTxAnimation",
|
||||
MakeCallback(&GanttTrace::FifoEntryTrace, this));
|
||||
}
|
||||
|
||||
void
|
||||
GanttTrace::DevTxTrace(std::string context,
|
||||
Ptr<const Packet> p,
|
||||
Ptr<NetDevice> tx,
|
||||
Ptr<NetDevice> rx,
|
||||
Time txTime,
|
||||
Time rxTime)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
NS_ASSERT(tx);
|
||||
NS_ASSERT(rx);
|
||||
|
||||
Time fbTx = Simulator::Now(); //Firt bit Tx time
|
||||
Time lbTx = fbTx + txTime; //Last bit Tx time
|
||||
Time fbRx = fbTx + rxTime - txTime; //First bit Rx time
|
||||
Time lbRx = fbTx + rxTime; //Last bit Rx time
|
||||
|
||||
|
||||
Ptr<Packet> copyPacket = p->Copy();
|
||||
EthernetHeader2 ethHeader;
|
||||
copyPacket->RemoveHeader(ethHeader);
|
||||
|
||||
// NS_LOG_INFO("CB TX triggered !");
|
||||
// NS_LOG_INFO(" SimTime : " << Simulator::Now().GetNanoSeconds() << "ns");
|
||||
// NS_LOG_INFO(" From NetDevice : " << Names::FindName(tx));
|
||||
// NS_LOG_INFO(" To NetDevice : " << Names::FindName(rx));
|
||||
// NS_LOG_INFO(" tx time : " << fbTx.GetNanoSeconds());
|
||||
// NS_LOG_INFO(" rx time : " << lbRx.GetNanoSeconds());
|
||||
// NS_LOG_INFO(" Pkt id : " << int(p->GetUid()));
|
||||
// NS_LOG_INFO(" Pkt vlanId: " << ethHeader.GetVid());
|
||||
// NS_LOG_INFO(" Pkt prio : " << int(ethHeader.GetPcp()));
|
||||
|
||||
WritePacketTxEvent(Names::FindName(tx), Names::FindName(rx), fbTx, lbTx, fbRx, lbRx, p->GetUid(), ethHeader.GetVid(), ethHeader.GetPcp());
|
||||
}
|
||||
|
||||
void
|
||||
GanttTrace::FifoEntryTrace(std::string context,
|
||||
Ptr<const Packet> p,
|
||||
Ptr<NetDevice> net)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
|
||||
// NS_LOG_INFO("CB : Pkt enter a FIFO !");
|
||||
// NS_LOG_INFO(" SimTime : " << Simulator::Now().GetNanoSeconds() << "ns");
|
||||
// NS_LOG_INFO(" On NetDevice : " << Names::FindName(net));
|
||||
// NS_LOG_INFO(" Pkt id : " << int(p->GetUid()));
|
||||
|
||||
Ptr<Packet> copyPacket = p->Copy();
|
||||
EthernetHeader2 ethHeader;
|
||||
copyPacket->RemoveHeader(ethHeader);
|
||||
|
||||
WriteFifoEnterEvent(Simulator::Now(), Names::FindName(net), int(p->GetUid()), ethHeader.GetPcp());
|
||||
}
|
||||
|
||||
void
|
||||
GanttTrace::WritePacketTxEvent(std::string srcNetDeviceName,
|
||||
std::string dstNetDeviceName,
|
||||
Time txBeginTime,
|
||||
Time txEndTime,
|
||||
Time rxBeginTime,
|
||||
Time rxEndTime,
|
||||
int pktId,
|
||||
int vlanId,
|
||||
int prio)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
|
||||
WriteN("TxEvent, pktId=" + std::to_string(pktId) +
|
||||
",src=" + srcNetDeviceName +
|
||||
", dst=" + dstNetDeviceName +
|
||||
", txBegin=" + std::to_string(txBeginTime.GetNanoSeconds()) +
|
||||
", txEnd=" + std::to_string(txEndTime.GetNanoSeconds()) +
|
||||
", rxBegin=" + std::to_string(rxBeginTime.GetNanoSeconds()) +
|
||||
", rxEnd=" + std::to_string(rxEndTime.GetNanoSeconds()) +
|
||||
", vlanId=" + std::to_string(vlanId) +
|
||||
", prio=" + std::to_string(prio) +
|
||||
"\n", m_f);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
GanttTrace::WriteFifoEnterEvent(Time t, std::string netDeviceName, int pktId, int fifoId)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
|
||||
WriteN("FifoEnterEvent, pktId=" + std::to_string(pktId) +
|
||||
", src=" + netDeviceName +
|
||||
", t=" + std::to_string(t.GetNanoSeconds()) +
|
||||
", fifoId=" + std::to_string(fifoId) +
|
||||
"\n", m_f);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
GanttTrace::WriteN(const std::string& st, FILE* f)
|
||||
{
|
||||
if (!f)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return WriteN(st.c_str(), st.length(), f);
|
||||
}
|
||||
|
||||
int
|
||||
GanttTrace::WriteN(const char* data, uint32_t count, FILE* f)
|
||||
{
|
||||
if (!f)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
// Write count bytes to h from data
|
||||
uint32_t nLeft = count;
|
||||
const char* p = data;
|
||||
uint32_t written = 0;
|
||||
while (nLeft)
|
||||
{
|
||||
int n = std::fwrite(p, 1, nLeft, f);
|
||||
if (n <= 0)
|
||||
{
|
||||
return written;
|
||||
}
|
||||
written += n;
|
||||
nLeft -= n;
|
||||
p += n;
|
||||
}
|
||||
return written;
|
||||
}
|
||||
|
||||
std::string
|
||||
GanttTrace::GetPacketMetadata(Ptr<const Packet> p)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
std::ostringstream oss;
|
||||
p->Print(oss);
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
}
|
||||
86
contrib/trace/model/gantt-trace.h
Normal file
86
contrib/trace/model/gantt-trace.h
Normal file
@@ -0,0 +1,86 @@
|
||||
#ifndef GANTT_TRACE_H
|
||||
#define GANTT_TRACE_H
|
||||
|
||||
#include "ns3/object.h"
|
||||
#include "ns3/config.h"
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/net-device.h"
|
||||
#include "ns3/node-list.h"
|
||||
#include "ns3/nstime.h"
|
||||
#include "ns3/ptr.h"
|
||||
#include "ns3/simulator.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
|
||||
// Add a doxygen group for this module.
|
||||
// If you have more than one file, this should be in only one of them.
|
||||
/**
|
||||
* \defgroup gantt-trace Description of the gantt-trace
|
||||
*/
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
class GanttTrace : public Object
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \brief Constructor
|
||||
* \param filename The Filename for the trace file used by the Animator
|
||||
*
|
||||
*/
|
||||
GanttTrace(const std::string filename);
|
||||
|
||||
/**
|
||||
* \brief Destructor for the animator interface.
|
||||
*
|
||||
*/
|
||||
~GanttTrace();
|
||||
|
||||
|
||||
void StartGantt();
|
||||
void StopGantt();
|
||||
|
||||
private:
|
||||
void SetOutputFile(const std::string& fn);
|
||||
|
||||
|
||||
void ConnectCallbacks();
|
||||
void DevTxTrace(std::string context,
|
||||
Ptr<const Packet> p,
|
||||
Ptr<NetDevice> tx,
|
||||
Ptr<NetDevice> rx,
|
||||
Time txTime,
|
||||
Time rxTime);
|
||||
void FifoEntryTrace(std::string context,
|
||||
Ptr<const Packet> p,
|
||||
Ptr<NetDevice> net);
|
||||
|
||||
void WritePacketTxEvent(std::string srcNetDeviceName,
|
||||
std::string dstNetDeviceName,
|
||||
Time txBeginTime,
|
||||
Time txEndTime,
|
||||
Time rxBeginTime,
|
||||
Time rxEndTime,
|
||||
int pktId,
|
||||
int vlanId,
|
||||
int prio);
|
||||
|
||||
void WriteFifoEnterEvent(Time t,
|
||||
std::string netDeviceName,
|
||||
int pktId,
|
||||
int fifoId);
|
||||
|
||||
int WriteN(const std::string& st, FILE* f);
|
||||
int WriteN(const char* data, uint32_t count, FILE* f);
|
||||
|
||||
std::string GetPacketMetadata(Ptr<const Packet> p);
|
||||
|
||||
std::string m_outputFileName;
|
||||
FILE* m_f;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* GANTT_TRACE_H */
|
||||
20
contrib/trace/test/examples-to-run.py
Normal file
20
contrib/trace/test/examples-to-run.py
Normal file
@@ -0,0 +1,20 @@
|
||||
#! /usr/bin/env python3
|
||||
|
||||
# A list of C++ examples to run in order to ensure that they remain
|
||||
# buildable and runnable over time. Each tuple in the list contains
|
||||
#
|
||||
# (example_name, do_run, do_valgrind_run).
|
||||
#
|
||||
# See test.py for more information.
|
||||
cpp_examples = [
|
||||
("tsn-point2point-netanim", "True", "True"),
|
||||
("tsn-switched-withFRER-netanim", "True", "True"),
|
||||
]
|
||||
|
||||
# A list of Python examples to run in order to ensure that they remain
|
||||
# runnable over time. Each tuple in the list contains
|
||||
#
|
||||
# (example_name, do_run).
|
||||
#
|
||||
# See test.py for more information.
|
||||
python_examples = []
|
||||
86
contrib/trace/test/trace-test-suite.cc
Normal file
86
contrib/trace/test/trace-test-suite.cc
Normal file
@@ -0,0 +1,86 @@
|
||||
|
||||
// Include a header file from your module to test.
|
||||
#include "ns3/animation-trace.h"
|
||||
|
||||
// An essential include is test.h
|
||||
#include "ns3/test.h"
|
||||
|
||||
// Do not put your test classes in namespace ns3. You may find it useful
|
||||
// to use the using directive to access the ns3 namespace directly
|
||||
using namespace ns3;
|
||||
|
||||
// Add a doxygen group for tests.
|
||||
// If you have more than one test, this should be in only one of them.
|
||||
/**
|
||||
* \defgroup animation-trace-tests Tests for animation-trace
|
||||
* \ingroup animation-trace
|
||||
* \ingroup tests
|
||||
*/
|
||||
|
||||
// This is an example TestCase.
|
||||
/**
|
||||
* \ingroup animation-trace-tests
|
||||
* Test case for feature 1
|
||||
*/
|
||||
class AnimationTraceTestCase1 : public TestCase
|
||||
{
|
||||
public:
|
||||
AnimationTraceTestCase1();
|
||||
virtual ~AnimationTraceTestCase1();
|
||||
|
||||
private:
|
||||
void DoRun() override;
|
||||
};
|
||||
|
||||
// Add some help text to this case to describe what it is intended to test
|
||||
AnimationTraceTestCase1::AnimationTraceTestCase1()
|
||||
: TestCase("AnimationTrace test case (does nothing)")
|
||||
{
|
||||
}
|
||||
|
||||
// This destructor does nothing but we include it as a reminder that
|
||||
// the test case should clean up after itself
|
||||
AnimationTraceTestCase1::~AnimationTraceTestCase1()
|
||||
{
|
||||
}
|
||||
|
||||
//
|
||||
// This method is the pure virtual method from class TestCase that every
|
||||
// TestCase must implement
|
||||
//
|
||||
void
|
||||
AnimationTraceTestCase1::DoRun()
|
||||
{
|
||||
// A wide variety of test macros are available in src/core/test.h
|
||||
NS_TEST_ASSERT_MSG_EQ(true, true, "true doesn't equal true for some reason");
|
||||
// Use this one for floating point comparisons
|
||||
NS_TEST_ASSERT_MSG_EQ_TOL(0.01, 0.01, 0.001, "Numbers are not equal within tolerance");
|
||||
}
|
||||
|
||||
// The TestSuite class names the TestSuite, identifies what type of TestSuite,
|
||||
// and enables the TestCases to be run. Typically, only the constructor for
|
||||
// this class must be defined
|
||||
|
||||
/**
|
||||
* \ingroup animation-trace-tests
|
||||
* TestSuite for module animation-trace
|
||||
*/
|
||||
class AnimationTraceTestSuite : public TestSuite
|
||||
{
|
||||
public:
|
||||
AnimationTraceTestSuite();
|
||||
};
|
||||
|
||||
AnimationTraceTestSuite::AnimationTraceTestSuite()
|
||||
: TestSuite("animation-trace", UNIT)
|
||||
{
|
||||
// TestDuration for TestCase can be QUICK, EXTENSIVE or TAKES_FOREVER
|
||||
AddTestCase(new AnimationTraceTestCase1, TestCase::QUICK);
|
||||
}
|
||||
|
||||
// Do not forget to allocate an instance of this TestSuite
|
||||
/**
|
||||
* \ingroup animation-trace-tests
|
||||
* Static variable for test initialization
|
||||
*/
|
||||
static AnimationTraceTestSuite sanimationTraceTestSuite;
|
||||
27
contrib/traffic-generator/CMakeLists.txt
Normal file
27
contrib/traffic-generator/CMakeLists.txt
Normal file
@@ -0,0 +1,27 @@
|
||||
check_include_file_cxx(stdint.h HAVE_STDINT_H)
|
||||
if(HAVE_STDINT_H)
|
||||
add_definitions(-DHAVE_STDINT_H)
|
||||
endif()
|
||||
|
||||
set(examples_as_tests_sources)
|
||||
if(${ENABLE_EXAMPLES})
|
||||
set(examples_as_tests_sources
|
||||
#test/traffic-generator-examples-test-suite.cc
|
||||
)
|
||||
endif()
|
||||
|
||||
build_lib(
|
||||
LIBNAME traffic-generator
|
||||
SOURCE_FILES model/traffic-generator.cc
|
||||
model/ethernet-generator.cc
|
||||
model/myCustomApp.cc
|
||||
helper/traffic-generator-helper.cc
|
||||
HEADER_FILES model/traffic-generator.h
|
||||
model/ethernet-generator.h
|
||||
model/myCustomApp.h
|
||||
helper/traffic-generator-helper.h
|
||||
LIBRARIES_TO_LINK ${libcore}
|
||||
${libethernet}
|
||||
TEST_SOURCES test/traffic-generator-test-suite.cc
|
||||
${examples_as_tests_sources}
|
||||
)
|
||||
7
contrib/traffic-generator/examples/CMakeLists.txt
Normal file
7
contrib/traffic-generator/examples/CMakeLists.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
build_lib_example(
|
||||
NAME traffic-generator-ethernet
|
||||
SOURCE_FILES traffic-generator-ethernet.cc
|
||||
LIBRARIES_TO_LINK ${libcore}
|
||||
${libnetwork}
|
||||
${libethernet}
|
||||
)
|
||||
@@ -0,0 +1,82 @@
|
||||
#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/ethernet-net-device.h"
|
||||
#include "ns3/ethernet-channel.h"
|
||||
#include "ns3/ethernet-generator.h"
|
||||
#include "ns3/ethernet-header2.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example of the use of ethernet-generator.cc on a network composed of two
|
||||
* ethernet end-stations
|
||||
* ES1 ====== ES2
|
||||
*/
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
//Enable logging
|
||||
LogComponentEnable("EthernetGenerator", LOG_LEVEL_INFO);
|
||||
CommandLine cmd(__FILE__);
|
||||
cmd.Parse(argc, argv);
|
||||
|
||||
//Create two nodes
|
||||
Ptr<Node> n0 = CreateObject<Node>();
|
||||
Names::Add("ES1", n0);
|
||||
Ptr<Node> n1 = CreateObject<Node>();
|
||||
Names::Add("ES2", n1);
|
||||
|
||||
//Create and add a netDevice to each node
|
||||
Ptr<EthernetNetDevice> net0 = CreateObject<EthernetNetDevice>();
|
||||
n0->AddDevice(net0);
|
||||
Names::Add("ES1#01", net0);
|
||||
Ptr<EthernetNetDevice> net1 = CreateObject<EthernetNetDevice>();
|
||||
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 two 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>>());
|
||||
|
||||
//Application description
|
||||
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
|
||||
app0->Setup(net0);
|
||||
app0->SetAttribute("Address", AddressValue(net1->GetAddress()));
|
||||
app0->SetAttribute("BurstSize", UintegerValue(2));
|
||||
app0->SetAttribute("PayloadSize", UintegerValue(1400));
|
||||
app0->SetAttribute("Period", TimeValue(Seconds(5)));
|
||||
app0->SetAttribute("InterFrame", TimeValue(MilliSeconds(200)));
|
||||
app0->SetAttribute("Offset", TimeValue(MilliSeconds(100)));
|
||||
app0->SetAttribute("VlanID", UintegerValue(100));
|
||||
app0->SetAttribute("PCP", UintegerValue(0));
|
||||
|
||||
n0->AddApplication(app0);
|
||||
app0->SetStartTime(Seconds(0));
|
||||
app0->SetStopTime(Seconds(10));
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(Seconds(10));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#include "traffic-generator-helper.h"
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
/* ... */
|
||||
|
||||
}
|
||||
16
contrib/traffic-generator/helper/traffic-generator-helper.h
Normal file
16
contrib/traffic-generator/helper/traffic-generator-helper.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifndef TRAFFIC_GENERATOR_HELPER_H
|
||||
#define TRAFFIC_GENERATOR_HELPER_H
|
||||
|
||||
#include "ns3/traffic-generator.h"
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
// Each class should be documented using Doxygen,
|
||||
// and have an \ingroup traffic-generator directive
|
||||
|
||||
/* ... */
|
||||
|
||||
}
|
||||
|
||||
#endif /* TRAFFIC_GENERATOR_HELPER_H */
|
||||
153
contrib/traffic-generator/model/ethernet-generator.cc
Normal file
153
contrib/traffic-generator/model/ethernet-generator.cc
Normal file
@@ -0,0 +1,153 @@
|
||||
#include "ethernet-generator.h"
|
||||
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/socket-factory.h"
|
||||
#include "ns3/socket.h"
|
||||
#include "ns3/uinteger.h"
|
||||
#include "ns3/names.h"
|
||||
#include "ns3/ethernet-net-device.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("EthernetGenerator");
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED(EthernetGenerator);
|
||||
|
||||
TypeId
|
||||
EthernetGenerator::GetTypeId()
|
||||
{
|
||||
static TypeId tid =
|
||||
TypeId("ns3::EthernetGenerator")
|
||||
.SetParent<Application>()
|
||||
.SetGroupName("Applications")
|
||||
.AddConstructor<EthernetGenerator>()
|
||||
.AddAttribute("Address",
|
||||
"Destination Mac Address",
|
||||
AddressValue(Mac48Address("ff:ff:ff:ff:ff:ff")),
|
||||
MakeAddressAccessor(&EthernetGenerator::m_destAddress),
|
||||
MakeAddressChecker())
|
||||
.AddAttribute("PayloadSize",
|
||||
"Payload Size in bytes",
|
||||
UintegerValue(100),
|
||||
MakeUintegerAccessor(&EthernetGenerator::m_payload_size),
|
||||
MakeUintegerChecker<uint16_t>())
|
||||
.AddAttribute("BurstSize",
|
||||
"Burst size",
|
||||
UintegerValue(1),
|
||||
MakeUintegerAccessor(&EthernetGenerator::m_burst_size),
|
||||
MakeUintegerChecker<uint16_t>())
|
||||
.AddAttribute("Period",
|
||||
"Period between burst",
|
||||
TimeValue(Seconds(1)),
|
||||
MakeTimeAccessor(&EthernetGenerator::m_period),
|
||||
MakeTimeChecker())
|
||||
.AddAttribute("InterFrame",
|
||||
"Period between two packet of a burst",
|
||||
TimeValue(Seconds(0)),
|
||||
MakeTimeAccessor(&EthernetGenerator::m_interframe),
|
||||
MakeTimeChecker())
|
||||
.AddAttribute("Offset",
|
||||
"Time offset between application start and first packet emission",
|
||||
TimeValue(Seconds(0)),
|
||||
MakeTimeAccessor(&EthernetGenerator::m_offset),
|
||||
MakeTimeChecker())
|
||||
.AddAttribute("VlanID",
|
||||
"Vlan ID",
|
||||
UintegerValue(65535),
|
||||
MakeUintegerAccessor(&EthernetGenerator::m_vid),
|
||||
MakeUintegerChecker<uint16_t>())
|
||||
.AddAttribute("PCP",
|
||||
"PCP field",
|
||||
UintegerValue(0),
|
||||
MakeUintegerAccessor(&EthernetGenerator::m_pcp),
|
||||
MakeUintegerChecker<uint8_t>())
|
||||
.AddAttribute("DEI",
|
||||
"DEI bit",
|
||||
UintegerValue(0),
|
||||
MakeUintegerAccessor(&EthernetGenerator::m_dei),
|
||||
MakeUintegerChecker<uint8_t>())
|
||||
.AddTraceSource("PktSent",
|
||||
"Trace source indicating a packet was given to the netDevice"
|
||||
"by the application",
|
||||
MakeTraceSourceAccessor(&EthernetGenerator::m_pktSentTrace),
|
||||
"ns3::EthernetGenerator::PacketVlanTraceCallback");
|
||||
return tid;
|
||||
}
|
||||
|
||||
EthernetGenerator::EthernetGenerator()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
m_net = nullptr;
|
||||
}
|
||||
|
||||
EthernetGenerator::~EthernetGenerator()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
}
|
||||
|
||||
void
|
||||
EthernetGenerator::Setup(Ptr<EthernetNetDevice> net)
|
||||
{
|
||||
m_net = net;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
EthernetGenerator::DoDispose()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
Application::DoDispose();
|
||||
}
|
||||
|
||||
void
|
||||
EthernetGenerator::StartApplication()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
if (m_vid==65535 && m_payload_size < MIN_PAYLOAD_SIZE + 4){
|
||||
m_payload_size = MIN_PAYLOAD_SIZE + 4;
|
||||
}
|
||||
else if(m_payload_size < MIN_PAYLOAD_SIZE){
|
||||
m_payload_size = MIN_PAYLOAD_SIZE;
|
||||
}
|
||||
m_sendEvent = Simulator::Schedule(m_offset, &EthernetGenerator::SendBurst, this);
|
||||
}
|
||||
|
||||
void
|
||||
EthernetGenerator::StopApplication()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
Simulator::Cancel(m_sendEvent);
|
||||
}
|
||||
|
||||
void
|
||||
EthernetGenerator::SendBurst()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
for (int i = 0; i < m_burst_size; i++) {
|
||||
Simulator::Schedule(m_interframe*i, &EthernetGenerator::Send, this);
|
||||
}
|
||||
m_sendEvent = Simulator::Schedule(m_period, &EthernetGenerator::SendBurst, this);
|
||||
}
|
||||
|
||||
void
|
||||
EthernetGenerator::Send()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
|
||||
Ptr<Packet> p = Create<Packet>(m_payload_size);
|
||||
//NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << Names::FindName(m_net->GetNode()) << "/" << Names::FindName(m_net) <<" : Pkt #" << p->GetUid() <<"(vid="<< m_vid <<") given to the netDevice ! " << p->ToString());
|
||||
if (m_vid==65535){
|
||||
m_net->Send(p, m_destAddress, 0xEDE1);
|
||||
}
|
||||
else{
|
||||
m_net->Send(p, m_destAddress, 0xEDE1, m_vid, m_pcp, m_dei);
|
||||
}
|
||||
m_pktSentTrace(p, m_vid);
|
||||
}
|
||||
|
||||
} // Namespace ns3
|
||||
72
contrib/traffic-generator/model/ethernet-generator.h
Normal file
72
contrib/traffic-generator/model/ethernet-generator.h
Normal file
@@ -0,0 +1,72 @@
|
||||
#ifndef ETHERNET_GENERATOR_H
|
||||
#define ETHERNET_GENERATOR_H
|
||||
|
||||
#include "ns3/application.h"
|
||||
#include "ns3/event-id.h"
|
||||
#include "ns3/ptr.h"
|
||||
#include <ns3/traced-callback.h>
|
||||
#include "ns3/ethernet-net-device.h"
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
class Socket;
|
||||
class Packet;
|
||||
|
||||
|
||||
class EthernetGenerator : public Application
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \brief Get the type ID.
|
||||
* \return the object TypeId
|
||||
*/
|
||||
static TypeId GetTypeId();
|
||||
|
||||
EthernetGenerator();
|
||||
|
||||
~EthernetGenerator() override;
|
||||
|
||||
/**
|
||||
* \return the total bytes sent by this app
|
||||
*/
|
||||
|
||||
void Setup(Ptr<EthernetNetDevice> net);
|
||||
|
||||
typedef TracedCallback<Ptr<const Packet>, uint16_t> PacketVlanTraceCallback;
|
||||
|
||||
protected:
|
||||
void DoDispose() override;
|
||||
|
||||
private:
|
||||
void StartApplication() override;
|
||||
void StopApplication() override;
|
||||
|
||||
/**
|
||||
* \brief Send a packet
|
||||
*/
|
||||
void SendBurst();
|
||||
void Send();
|
||||
|
||||
Address m_destAddress;
|
||||
int m_payload_size;
|
||||
int m_burst_size;
|
||||
Time m_period;
|
||||
Time m_interframe;
|
||||
Time m_offset;
|
||||
|
||||
uint16_t m_vid;
|
||||
uint8_t m_pcp;
|
||||
uint8_t m_dei;
|
||||
|
||||
EventId m_sendEvent; //!< Event to send the next packet
|
||||
Ptr<EthernetNetDevice> m_net;
|
||||
|
||||
PacketVlanTraceCallback m_pktSentTrace;
|
||||
|
||||
static const uint16_t MIN_PAYLOAD_SIZE = 42; //Min payload size with VLAN
|
||||
};
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif
|
||||
119
contrib/traffic-generator/model/myCustomApp.cc
Normal file
119
contrib/traffic-generator/model/myCustomApp.cc
Normal file
@@ -0,0 +1,119 @@
|
||||
#include "myCustomApp.h"
|
||||
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/socket-factory.h"
|
||||
#include "ns3/socket.h"
|
||||
#include "ns3/uinteger.h"
|
||||
#include "ns3/names.h"
|
||||
#include "ns3/point-to-point-net-device.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("myCustomApp");
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED(myCustomApp);
|
||||
|
||||
TypeId
|
||||
myCustomApp::GetTypeId()
|
||||
{
|
||||
static TypeId tid =
|
||||
TypeId("ns3::myCustomApp")
|
||||
.SetParent<Application>()
|
||||
.SetGroupName("Applications")
|
||||
.AddConstructor<myCustomApp>();
|
||||
return tid;
|
||||
}
|
||||
|
||||
myCustomApp::myCustomApp()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
m_sent = 0;
|
||||
m_totalTx = 0;
|
||||
m_totalRx = 0;
|
||||
m_sendEvent = EventId();
|
||||
}
|
||||
|
||||
myCustomApp::~myCustomApp()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
}
|
||||
|
||||
void
|
||||
myCustomApp::Setup(Ptr<PointToPointNetDevice> net, int t)
|
||||
{
|
||||
m_net = net;
|
||||
Packet::EnablePrinting();
|
||||
m_sendEvent = Simulator::Schedule(Seconds(t), &myCustomApp::Send, this);
|
||||
m_net->SetReceiveCallback(MakeCallback(&myCustomApp::RxPacket, this));
|
||||
}
|
||||
|
||||
bool
|
||||
myCustomApp::RxPacket(Ptr<NetDevice> dev, Ptr<const Packet> pkt, uint16_t mode, const Address& sender)
|
||||
{
|
||||
m_totalRx = m_totalRx + pkt->GetSize();
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << Names::FindName(m_net->GetNode()) << "/" << Names::FindName(m_net) <<" : Pkt rcvd ! " << pkt->ToString());
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
myCustomApp::DoDispose()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
Application::DoDispose();
|
||||
}
|
||||
|
||||
void
|
||||
myCustomApp::StartApplication()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
myCustomApp::StopApplication()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
Simulator::Cancel(m_sendEvent);
|
||||
NS_LOG_INFO("\tNb bytes rcvd :" << GetTotalRx());
|
||||
}
|
||||
|
||||
void
|
||||
myCustomApp::Send()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
NS_ASSERT(m_sendEvent.IsExpired());
|
||||
|
||||
|
||||
uint8_t txBuffer[] = "\"Can you tell me where my country lies?\" \\ said the unifaun to his "
|
||||
"true love's eyes. \\ \"It lies with me!\" cried the Queen of Maybe \\ - "
|
||||
"for her merchandise, he traded in his prize.";
|
||||
size_t txBufferSize = sizeof(txBuffer);
|
||||
Ptr<Packet> p = Create<Packet>(txBuffer, txBufferSize);
|
||||
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << Names::FindName(m_net->GetNode()) << "/" << Names::FindName(m_net) <<" : Pkt sent ! " << p->ToString());
|
||||
|
||||
m_net->Send(p, m_net->GetBroadcast(), 0x800);
|
||||
|
||||
m_sendEvent = Simulator::Schedule(Seconds(2), &myCustomApp::Send, this);
|
||||
|
||||
}
|
||||
|
||||
uint64_t
|
||||
myCustomApp::GetTotalTx() const
|
||||
{
|
||||
return m_totalTx;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
myCustomApp::GetTotalRx() const
|
||||
{
|
||||
return m_totalRx;
|
||||
}
|
||||
|
||||
} // Namespace ns3
|
||||
66
contrib/traffic-generator/model/myCustomApp.h
Normal file
66
contrib/traffic-generator/model/myCustomApp.h
Normal file
@@ -0,0 +1,66 @@
|
||||
#ifndef MY_CUSTOM_APP_H
|
||||
#define MY_CUSTOM_APP_H
|
||||
|
||||
#include "ns3/application.h"
|
||||
#include "ns3/event-id.h"
|
||||
#include "ns3/ptr.h"
|
||||
#include <ns3/traced-callback.h>
|
||||
#include "ns3/point-to-point-net-device.h"
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
class Socket;
|
||||
class Packet;
|
||||
|
||||
|
||||
class myCustomApp : public Application
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \brief Get the type ID.
|
||||
* \return the object TypeId
|
||||
*/
|
||||
static TypeId GetTypeId();
|
||||
|
||||
myCustomApp();
|
||||
|
||||
~myCustomApp() override;
|
||||
|
||||
/**
|
||||
* \return the total bytes sent by this app
|
||||
*/
|
||||
uint64_t GetTotalTx() const;
|
||||
uint64_t GetTotalRx() const;
|
||||
|
||||
void Setup(Ptr<PointToPointNetDevice> net, int t);
|
||||
bool RxPacket(Ptr<NetDevice> dev, Ptr<const Packet> pkt, uint16_t mode, const Address& sender);
|
||||
|
||||
protected:
|
||||
void DoDispose() override;
|
||||
|
||||
private:
|
||||
void StartApplication() override;
|
||||
void StopApplication() override;
|
||||
|
||||
/**
|
||||
* \brief Send a packet
|
||||
*/
|
||||
void Send();
|
||||
|
||||
uint32_t m_count; //!< Maximum number of packets the application will send
|
||||
Time m_interval; //!< Packet inter-send time
|
||||
uint32_t m_size; //!< Size of the sent packet (including the SeqTsHeader)
|
||||
|
||||
uint32_t m_sent; //!< Counter for sent packets
|
||||
uint64_t m_totalRx; //!< Total bytes sent
|
||||
uint64_t m_totalTx; //!< Total bytes rcvd
|
||||
Address m_peerAddress; //!< Remote peer address
|
||||
uint16_t m_peerPort; //!< Remote peer port
|
||||
EventId m_sendEvent; //!< Event to send the next packet
|
||||
Ptr<PointToPointNetDevice> m_net;
|
||||
};
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif
|
||||
8
contrib/traffic-generator/model/traffic-generator.cc
Normal file
8
contrib/traffic-generator/model/traffic-generator.cc
Normal file
@@ -0,0 +1,8 @@
|
||||
#include "traffic-generator.h"
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
/* ... */
|
||||
|
||||
}
|
||||
20
contrib/traffic-generator/model/traffic-generator.h
Normal file
20
contrib/traffic-generator/model/traffic-generator.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef TRAFFIC_GENERATOR_H
|
||||
#define TRAFFIC_GENERATOR_H
|
||||
|
||||
// Add a doxygen group for this module.
|
||||
// If you have more than one file, this should be in only one of them.
|
||||
/**
|
||||
* \defgroup traffic-generator Description of the traffic-generator
|
||||
*/
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
// Each class should be documented using Doxygen,
|
||||
// and have an \ingroup traffic-generator directive
|
||||
|
||||
/* ... */
|
||||
|
||||
}
|
||||
|
||||
#endif /* TRAFFIC_GENERATOR_H */
|
||||
19
contrib/traffic-generator/test/examples-to-run.py
Normal file
19
contrib/traffic-generator/test/examples-to-run.py
Normal file
@@ -0,0 +1,19 @@
|
||||
#! /usr/bin/env python3
|
||||
|
||||
# A list of C++ examples to run in order to ensure that they remain
|
||||
# buildable and runnable over time. Each tuple in the list contains
|
||||
#
|
||||
# (example_name, do_run, do_valgrind_run).
|
||||
#
|
||||
# See test.py for more information.
|
||||
cpp_examples = [
|
||||
("traffic-generator-ethernet", "True", "True"),
|
||||
]
|
||||
|
||||
# A list of Python examples to run in order to ensure that they remain
|
||||
# runnable over time. Each tuple in the list contains
|
||||
#
|
||||
# (example_name, do_run).
|
||||
#
|
||||
# See test.py for more information.
|
||||
python_examples = []
|
||||
@@ -0,0 +1,86 @@
|
||||
|
||||
// Include a header file from your module to test.
|
||||
#include "ns3/traffic-generator.h"
|
||||
|
||||
// An essential include is test.h
|
||||
#include "ns3/test.h"
|
||||
|
||||
// Do not put your test classes in namespace ns3. You may find it useful
|
||||
// to use the using directive to access the ns3 namespace directly
|
||||
using namespace ns3;
|
||||
|
||||
// Add a doxygen group for tests.
|
||||
// If you have more than one test, this should be in only one of them.
|
||||
/**
|
||||
* \defgroup traffic-generator-tests Tests for traffic-generator
|
||||
* \ingroup traffic-generator
|
||||
* \ingroup tests
|
||||
*/
|
||||
|
||||
// This is an example TestCase.
|
||||
/**
|
||||
* \ingroup traffic-generator-tests
|
||||
* Test case for feature 1
|
||||
*/
|
||||
class TrafficGeneratorTestCase1 : public TestCase
|
||||
{
|
||||
public:
|
||||
TrafficGeneratorTestCase1();
|
||||
virtual ~TrafficGeneratorTestCase1();
|
||||
|
||||
private:
|
||||
void DoRun() override;
|
||||
};
|
||||
|
||||
// Add some help text to this case to describe what it is intended to test
|
||||
TrafficGeneratorTestCase1::TrafficGeneratorTestCase1()
|
||||
: TestCase("TrafficGenerator test case (does nothing)")
|
||||
{
|
||||
}
|
||||
|
||||
// This destructor does nothing but we include it as a reminder that
|
||||
// the test case should clean up after itself
|
||||
TrafficGeneratorTestCase1::~TrafficGeneratorTestCase1()
|
||||
{
|
||||
}
|
||||
|
||||
//
|
||||
// This method is the pure virtual method from class TestCase that every
|
||||
// TestCase must implement
|
||||
//
|
||||
void
|
||||
TrafficGeneratorTestCase1::DoRun()
|
||||
{
|
||||
// A wide variety of test macros are available in src/core/test.h
|
||||
NS_TEST_ASSERT_MSG_EQ(true, true, "true doesn't equal true for some reason");
|
||||
// Use this one for floating point comparisons
|
||||
NS_TEST_ASSERT_MSG_EQ_TOL(0.01, 0.01, 0.001, "Numbers are not equal within tolerance");
|
||||
}
|
||||
|
||||
// The TestSuite class names the TestSuite, identifies what type of TestSuite,
|
||||
// and enables the TestCases to be run. Typically, only the constructor for
|
||||
// this class must be defined
|
||||
|
||||
/**
|
||||
* \ingroup traffic-generator-tests
|
||||
* TestSuite for module traffic-generator
|
||||
*/
|
||||
class TrafficGeneratorTestSuite : public TestSuite
|
||||
{
|
||||
public:
|
||||
TrafficGeneratorTestSuite();
|
||||
};
|
||||
|
||||
TrafficGeneratorTestSuite::TrafficGeneratorTestSuite()
|
||||
: TestSuite("traffic-generator", UNIT)
|
||||
{
|
||||
// TestDuration for TestCase can be QUICK, EXTENSIVE or TAKES_FOREVER
|
||||
AddTestCase(new TrafficGeneratorTestCase1, TestCase::QUICK);
|
||||
}
|
||||
|
||||
// Do not forget to allocate an instance of this TestSuite
|
||||
/**
|
||||
* \ingroup traffic-generator-tests
|
||||
* Static variable for test initialization
|
||||
*/
|
||||
static TrafficGeneratorTestSuite strafficGeneratorTestSuite;
|
||||
84
contrib/tsn/CMakeLists.txt
Normal file
84
contrib/tsn/CMakeLists.txt
Normal file
@@ -0,0 +1,84 @@
|
||||
check_include_file_cxx(stdint.h HAVE_STDINT_H)
|
||||
if(HAVE_STDINT_H)
|
||||
add_definitions(-DHAVE_STDINT_H)
|
||||
endif()
|
||||
|
||||
set(examples_as_tests_sources)
|
||||
if(${ENABLE_EXAMPLES})
|
||||
set(examples_as_tests_sources
|
||||
#test/tsn-examples-test-suite.cc
|
||||
)
|
||||
endif()
|
||||
|
||||
build_lib(
|
||||
LIBNAME tsn
|
||||
SOURCE_FILES model/tsn-node.cc
|
||||
model/tsn-net-device.cc
|
||||
model/tsn-aggregated-net-device.cc
|
||||
model/tsn-multidrop-channel.cc
|
||||
model/transmission-gate.cc
|
||||
model/tsn-multidrop-net-device.cc
|
||||
model/tas.cc
|
||||
model/tsn-transmission-selection-algo.cc
|
||||
model/cbs.cc
|
||||
model/clock.cc
|
||||
model/clock-constant-drift.cc
|
||||
model/clock-virtual.cc
|
||||
model/clock-fix-precision.cc
|
||||
model/gPTP.cc
|
||||
model/gPTP-header.cc
|
||||
model/gPTP-packet.cc
|
||||
model/stream-identity-entry.cc
|
||||
model/stream-identification-function.cc
|
||||
model/stream-identification-function-null.cc
|
||||
model/stream-identification-function-active-dest-mac-vlan.cc
|
||||
model/frer-sequence-encode-decode-function.cc
|
||||
model/frer-sequence-generation-function.cc
|
||||
model/frer-sequence-recovery-function.cc
|
||||
model/frer-base-recovery-function.cc
|
||||
model/frer-match-recovery-function.cc
|
||||
model/frer-vector-recovery-function.cc
|
||||
model/frer-latent-error-detection-function.cc
|
||||
model/psfp-stream-filter-instance.cc
|
||||
model/psfp-flow-meter-instance.cc
|
||||
helper/tsn-helper.cc
|
||||
HEADER_FILES model/tsn-node.h
|
||||
model/tsn-net-device.h
|
||||
model/tsn-aggregated-net-device.h
|
||||
model/tsn-multidrop-channel.h
|
||||
model/tsn-multidrop-net-device.h
|
||||
model/transmission-gate.h
|
||||
model/tas.h
|
||||
model/tsn-transmission-selection-algo.h
|
||||
model/cbs.h
|
||||
model/clock.h
|
||||
model/clock-constant-drift.h
|
||||
model/clock-fix-precision.h
|
||||
model/clock-virtual.h
|
||||
model/gPTP.h
|
||||
model/gPTP-header.h
|
||||
model/gPTP-packet.h
|
||||
model/stream-identity-entry.h
|
||||
model/stream-identification-function.h
|
||||
model/stream-identification-function-null.h
|
||||
model/stream-identification-function-active-dest-mac-vlan.h
|
||||
model/frer-sequence-encode-decode-function.h
|
||||
model/frer-sequence-generation-function.h
|
||||
model/frer-sequence-recovery-function.h
|
||||
model/frer-base-recovery-function.h
|
||||
model/frer-match-recovery-function.h
|
||||
model/frer-vector-recovery-function.h
|
||||
model/frer-latent-error-detection-function.h
|
||||
model/psfp-stream-filter-instance.h
|
||||
model/psfp-flow-meter-instance.h
|
||||
helper/tsn-helper.h
|
||||
LIBRARIES_TO_LINK ${libcore}
|
||||
${libethernet}
|
||||
TEST_SOURCES test/tsn-test-suite.cc
|
||||
test/cbs-test-suite.cc
|
||||
test/tas-test-suite.cc
|
||||
test/frer-test-suite.cc
|
||||
test/psfp-test-suite.cc
|
||||
test/tsn-multidrop-test-suite.cc
|
||||
${examples_as_tests_sources}
|
||||
)
|
||||
36
contrib/tsn/examples/CMakeLists.txt
Normal file
36
contrib/tsn/examples/CMakeLists.txt
Normal file
@@ -0,0 +1,36 @@
|
||||
set(base_examples
|
||||
tsn-point2point
|
||||
tsn-point2point-withCBS
|
||||
tsn-point2point-withTAS
|
||||
tsn-point2point-withTAS-CBS
|
||||
tsn-point2point-withTAS-gPTP
|
||||
tsn-point2point-withTAS-GuardBand
|
||||
tsn-point2point-withPSFP-MaxSDUSizeFilter
|
||||
tsn-point2point-withPSFP-FlowMeter
|
||||
tsn-switched-withFRER
|
||||
tsn-switched-withFRER-recoveryAlgo
|
||||
tsn-switched-withFRER-activeSid
|
||||
tsn-point2point-withGPTP
|
||||
tsn-point2point-withGPTP-Multidomain
|
||||
tsn-point2point-withGPTP-fixPrecisionClock
|
||||
tsn-switched-withGPTP
|
||||
tsn-multidrop
|
||||
tsn-multidrop-withCBS
|
||||
tsn-multidrop-withTAS
|
||||
tsn-multidrop-withTAS-CBS
|
||||
tsn-switched-multidrop
|
||||
)
|
||||
foreach(
|
||||
example
|
||||
${base_examples}
|
||||
)
|
||||
build_lib_example(
|
||||
NAME ${example}
|
||||
SOURCE_FILES ${example}.cc
|
||||
LIBRARIES_TO_LINK ${libtsn}
|
||||
${libcore}
|
||||
${libnetwork}
|
||||
${libtraffic-generator}
|
||||
${libethernet}
|
||||
)
|
||||
endforeach()
|
||||
191
contrib/tsn/examples/tsn-multidrop-withCBS.cc
Normal file
191
contrib/tsn/examples/tsn-multidrop-withCBS.cc
Normal file
@@ -0,0 +1,191 @@
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/applications-module.h"
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/drop-tail-queue.h"
|
||||
#include "ns3/timestamp-tag.h"
|
||||
|
||||
#include "ns3/tsn-multidrop-net-device.h"
|
||||
#include "ns3/tsn-multidrop-channel.h"
|
||||
#include "ns3/ethernet-generator.h"
|
||||
#include "ns3/ethernet-header2.h"
|
||||
#include "ns3/cbs.h"
|
||||
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example of the use of tsn-net-device.cc tsn-multidrop-channel.cc on a network
|
||||
* composed of four end-stations connected by a 10Base-T1S with a CBS on the
|
||||
* highest priority FIFO of ES1
|
||||
* ES1 ====== ES2
|
||||
* ||
|
||||
* ||== ES3
|
||||
* ||
|
||||
* ||== ES4
|
||||
*/
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("Example");
|
||||
|
||||
|
||||
//A callback to log pkt fifo entry time
|
||||
static void
|
||||
MacTxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
Ptr<Packet> originalPacket = p->Copy();
|
||||
EthernetHeader2 ethHeader;
|
||||
originalPacket->RemoveHeader(ethHeader);
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << "(VID:" << ethHeader.GetVid() << ") entering the FIFO on the producer");
|
||||
}
|
||||
|
||||
//A callback to log the pkt latency
|
||||
static void
|
||||
LatencyCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
TimestampTag tag;
|
||||
if (!p->FindFirstMatchingByteTag(tag))
|
||||
{
|
||||
return;
|
||||
}
|
||||
Time arrival = Simulator::Now();
|
||||
Time latency = arrival - tag.GetTimestamp();
|
||||
|
||||
Ptr<Packet> originalPacket = p->Copy();
|
||||
EthernetHeader2 ethHeader;
|
||||
originalPacket->RemoveHeader(ethHeader);
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " received from " << ethHeader.GetSrc() << "(VID:" << ethHeader.GetVid() << ") with a latency=" << latency.GetNanoSeconds() <<"ns");
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
//Enable logging
|
||||
LogComponentEnable("Example", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("EthernetGenerator", LOG_LEVEL_INFO);
|
||||
// LogComponentEnable("TsnMultidropNetDevice", LOG_LEVEL_INFO);
|
||||
// LogComponentEnable("TsnMultidropChannel", LOG_LEVEL_INFO);
|
||||
|
||||
CommandLine cmd(__FILE__);
|
||||
cmd.Parse(argc, argv);
|
||||
|
||||
//Create four nodes
|
||||
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
|
||||
Names::Add("ES1", n0);
|
||||
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
|
||||
Names::Add("ES2", n1);
|
||||
Ptr<TsnNode> n2 = CreateObject<TsnNode>();
|
||||
Names::Add("ES3", n2);
|
||||
Ptr<TsnNode> n3 = CreateObject<TsnNode>();
|
||||
Names::Add("ES4", n3);
|
||||
|
||||
|
||||
//Create and add a netDevice to each node
|
||||
Ptr<TsnMultidropNetDevice> net0 = CreateObject<TsnMultidropNetDevice>();
|
||||
net0->SetAttribute("PLCALocalNodeId", UintegerValue(0));
|
||||
net0->SetAttribute("PLCANodeCount", UintegerValue(4));
|
||||
// net0->SetAttribute("PLCAMaxBurstCount", UintegerValue(1));
|
||||
n0->AddDevice(net0);
|
||||
Names::Add("ES1#01", net0);
|
||||
Ptr<TsnMultidropNetDevice> net1 = CreateObject<TsnMultidropNetDevice>();
|
||||
net1->SetAttribute("PLCALocalNodeId", UintegerValue(1));
|
||||
net1->SetAttribute("PLCANodeCount", UintegerValue(4));
|
||||
n1->AddDevice(net1);
|
||||
Names::Add("ES2#01", net1);
|
||||
Ptr<TsnMultidropNetDevice> net2 = CreateObject<TsnMultidropNetDevice>();
|
||||
net2->SetAttribute("PLCALocalNodeId", UintegerValue(2));
|
||||
net2->SetAttribute("PLCANodeCount", UintegerValue(4));
|
||||
n2->AddDevice(net2);
|
||||
Names::Add("ES3#01", net2);
|
||||
Ptr<TsnMultidropNetDevice> net3 = CreateObject<TsnMultidropNetDevice>();
|
||||
net3->SetAttribute("PLCALocalNodeId", UintegerValue(3));
|
||||
net3->SetAttribute("PLCANodeCount", UintegerValue(4));
|
||||
n3->AddDevice(net3);
|
||||
Names::Add("ES4#01", net3);
|
||||
|
||||
|
||||
//Create a 10Base-T1S Channel and attach it two the netDevices
|
||||
Ptr<TsnMultidropChannel> channel = CreateObject<TsnMultidropChannel>();
|
||||
net0->Attach(channel);
|
||||
net1->Attach(channel);
|
||||
net2->Attach(channel);
|
||||
net3->Attach(channel);
|
||||
|
||||
|
||||
//Allocate a Mac address and create a FIFO (for the output port)
|
||||
//for each netDevice.
|
||||
net0->SetAddress(Mac48Address::Allocate());
|
||||
Ptr<Cbs> cbs = CreateObject<Cbs>();
|
||||
cbs->SetTsnNetDevice(net0);
|
||||
cbs->SetAttribute("IdleSlope", DataRateValue(DataRate("8Mb/s")));
|
||||
cbs->SetAttribute("portTransmitRate", DataRateValue(DataRate("10Mb/s")));
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>(), cbs);
|
||||
|
||||
net1->SetAddress(Mac48Address::Allocate());
|
||||
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
|
||||
net2->SetAddress(Mac48Address::Allocate());
|
||||
net2->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net2->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
|
||||
net3->SetAddress(Mac48Address::Allocate());
|
||||
net2->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net3->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
|
||||
|
||||
//Application description
|
||||
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
|
||||
app0->Setup(net0);
|
||||
app0->SetAttribute("BurstSize", UintegerValue(2));
|
||||
app0->SetAttribute("PayloadSize", UintegerValue(1400));
|
||||
app0->SetAttribute("Period", TimeValue(Seconds(5)));
|
||||
app0->SetAttribute("PCP", UintegerValue(1));
|
||||
app0->SetAttribute("VlanID", UintegerValue(1));
|
||||
|
||||
n0->AddApplication(app0);
|
||||
app0->SetStartTime(Seconds(0));
|
||||
app0->SetStopTime(Seconds(10));
|
||||
|
||||
|
||||
Ptr<EthernetGenerator> app1 = CreateObject<EthernetGenerator>();
|
||||
app1->Setup(net0);
|
||||
app1->SetAttribute("BurstSize", UintegerValue(2));
|
||||
app1->SetAttribute("PayloadSize", UintegerValue(1400));
|
||||
app1->SetAttribute("Period", TimeValue(Seconds(5)));
|
||||
app1->SetAttribute("PCP", UintegerValue(0));
|
||||
app1->SetAttribute("VlanID", UintegerValue(2));
|
||||
|
||||
n0->AddApplication(app1);
|
||||
app1->SetStartTime(Seconds(0));
|
||||
app1->SetStopTime(Seconds(10));
|
||||
|
||||
|
||||
//Callback to log pkt fifo entry time
|
||||
std::string context = Names::FindName(n0) + ":" + Names::FindName(net0);
|
||||
net0->TraceConnectWithoutContext("MacTx", MakeBoundCallback(&MacTxCallback, context));
|
||||
context = Names::FindName(n1) + ":" + Names::FindName(net1);
|
||||
net1->TraceConnectWithoutContext("MacTx", MakeBoundCallback(&MacTxCallback, context));
|
||||
context = Names::FindName(n2) + ":" + Names::FindName(net2);
|
||||
net2->TraceConnectWithoutContext("MacTx", MakeBoundCallback(&MacTxCallback, context));
|
||||
context = Names::FindName(n3) + ":" + Names::FindName(net3);
|
||||
net3->TraceConnectWithoutContext("MacTx", MakeBoundCallback(&MacTxCallback, context));
|
||||
|
||||
//Callback to display the packet latency
|
||||
net0->TraceConnectWithoutContext("Latency", MakeBoundCallback(&LatencyCallback, context));
|
||||
context = Names::FindName(n1) + ":" + Names::FindName(net1);
|
||||
net1->TraceConnectWithoutContext("Latency", MakeBoundCallback(&LatencyCallback, context));
|
||||
context = Names::FindName(n2) + ":" + Names::FindName(net2);
|
||||
net2->TraceConnectWithoutContext("Latency", MakeBoundCallback(&LatencyCallback, context));
|
||||
context = Names::FindName(n3) + ":" + Names::FindName(net3);
|
||||
net3->TraceConnectWithoutContext("Latency", MakeBoundCallback(&LatencyCallback, context));
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(MilliSeconds(5));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
292
contrib/tsn/examples/tsn-multidrop-withTAS-CBS.cc
Normal file
292
contrib/tsn/examples/tsn-multidrop-withTAS-CBS.cc
Normal file
@@ -0,0 +1,292 @@
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/applications-module.h"
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/drop-tail-queue.h"
|
||||
#include "ns3/timestamp-tag.h"
|
||||
|
||||
#include "ns3/tsn-multidrop-net-device.h"
|
||||
#include "ns3/tsn-multidrop-channel.h"
|
||||
#include "ns3/ethernet-generator.h"
|
||||
#include "ns3/ethernet-header2.h"
|
||||
#include "ns3/cbs.h"
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example of the use of tsn-net-device.cc tsn-multidrop-channel.cc on a network
|
||||
* composed of four end-stations connected by a 10Base-T1S with TAS and CBS on
|
||||
* ES1 port
|
||||
*
|
||||
* ES1 ====== ES2
|
||||
* ||
|
||||
* ||== ES3
|
||||
* ||
|
||||
* ||== ES4
|
||||
*/
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("Example");
|
||||
|
||||
|
||||
//A callback to log pkt fifo entry time
|
||||
static void
|
||||
MacTxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
Ptr<Packet> originalPacket = p->Copy();
|
||||
EthernetHeader2 ethHeader;
|
||||
originalPacket->RemoveHeader(ethHeader);
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << "(VID:" << ethHeader.GetVid() << ") entering the FIFO on the producer");
|
||||
}
|
||||
|
||||
//A callback to log the pkt latency
|
||||
static void
|
||||
LatencyCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
TimestampTag tag;
|
||||
if (!p->FindFirstMatchingByteTag(tag))
|
||||
{
|
||||
return;
|
||||
}
|
||||
Time arrival = Simulator::Now();
|
||||
Time latency = arrival - tag.GetTimestamp();
|
||||
|
||||
Ptr<Packet> originalPacket = p->Copy();
|
||||
EthernetHeader2 ethHeader;
|
||||
originalPacket->RemoveHeader(ethHeader);
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " received from " << ethHeader.GetSrc() << "(VID:" << ethHeader.GetVid() << ") with a latency=" << latency.GetNanoSeconds() <<"ns");
|
||||
}
|
||||
|
||||
//A callback to log the PLCA state
|
||||
static void
|
||||
PLCAStateCallback(std::string context, TsnMultidropNetDevice::PLCAState state)
|
||||
{
|
||||
std::string stateStr = "";
|
||||
if ( state == TsnMultidropNetDevice::PLCAState::DISABLE)
|
||||
{
|
||||
stateStr = "DISABLE";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::RECOVER)
|
||||
{
|
||||
stateStr = "RECOVER";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::RESYNC)
|
||||
{
|
||||
stateStr = "RESYNC";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::SEND_BEACON)
|
||||
{
|
||||
stateStr = "SEND_BEACON";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::SYNCING)
|
||||
{
|
||||
stateStr = "SYNCING";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::WAIT_TO)
|
||||
{
|
||||
stateStr = "WAIT_TO";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::COMMIT)
|
||||
{
|
||||
stateStr = "COMMIT";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::TRANSMIT)
|
||||
{
|
||||
stateStr = "TRANSMIT";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::BURST)
|
||||
{
|
||||
stateStr = "BURST";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::RECEIVE)
|
||||
{
|
||||
stateStr = "RECEIVE";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::YIELD)
|
||||
{
|
||||
stateStr = "YIELD";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::ABORT)
|
||||
{
|
||||
stateStr = "ABORT";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::NEXT_TX_OPPORTUNITY)
|
||||
{
|
||||
stateStr = "NEXT_TX_OPPORTUNITY";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::EARLY_RECEIVE)
|
||||
{
|
||||
stateStr = "EARLY_RECEIVE";
|
||||
}
|
||||
else
|
||||
{
|
||||
stateStr = "UNKNOWN_STATE";
|
||||
}
|
||||
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : PLCAState => " << stateStr);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
//Enable logging
|
||||
LogComponentEnable("Example", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("EthernetGenerator", LOG_LEVEL_INFO);
|
||||
// LogComponentEnable("TsnMultidropNetDevice", LOG_LEVEL_INFO);
|
||||
// LogComponentEnable("TsnMultidropChannel", LOG_LEVEL_INFO);
|
||||
|
||||
CommandLine cmd(__FILE__);
|
||||
cmd.Parse(argc, argv);
|
||||
|
||||
//Create four nodes
|
||||
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
|
||||
Names::Add("ES1", n0);
|
||||
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
|
||||
Names::Add("ES2", n1);
|
||||
Ptr<TsnNode> n2 = CreateObject<TsnNode>();
|
||||
Names::Add("ES3", n2);
|
||||
Ptr<TsnNode> n3 = CreateObject<TsnNode>();
|
||||
Names::Add("ES4", n3);
|
||||
|
||||
//Add perfect clock on each node
|
||||
n0->AddClock(CreateObject<Clock>());
|
||||
n1->AddClock(CreateObject<Clock>());
|
||||
n2->AddClock(CreateObject<Clock>());
|
||||
n3->AddClock(CreateObject<Clock>());
|
||||
|
||||
|
||||
//Create and add a netDevice to each node
|
||||
Ptr<TsnMultidropNetDevice> net0 = CreateObject<TsnMultidropNetDevice>();
|
||||
net0->SetAttribute("DataRate", DataRateValue(DataRate("10Mb/s")));
|
||||
net0->SetAttribute("PLCALocalNodeId", UintegerValue(0));
|
||||
net0->SetAttribute("PLCANodeCount", UintegerValue(4));
|
||||
// net0->SetAttribute("PLCAMaxBurstCount", UintegerValue(1));
|
||||
n0->AddDevice(net0);
|
||||
Names::Add("ES1#01", net0);
|
||||
Ptr<TsnMultidropNetDevice> net1 = CreateObject<TsnMultidropNetDevice>();
|
||||
net1->SetAttribute("DataRate", DataRateValue(DataRate("10Mb/s")));
|
||||
net1->SetAttribute("PLCALocalNodeId", UintegerValue(1));
|
||||
net1->SetAttribute("PLCANodeCount", UintegerValue(4));
|
||||
n1->AddDevice(net1);
|
||||
Names::Add("ES2#01", net1);
|
||||
Ptr<TsnMultidropNetDevice> net2 = CreateObject<TsnMultidropNetDevice>();
|
||||
net2->SetAttribute("DataRate", DataRateValue(DataRate("10Mb/s")));
|
||||
net2->SetAttribute("PLCALocalNodeId", UintegerValue(2));
|
||||
net2->SetAttribute("PLCANodeCount", UintegerValue(4));
|
||||
n2->AddDevice(net2);
|
||||
Names::Add("ES3#01", net2);
|
||||
Ptr<TsnMultidropNetDevice> net3 = CreateObject<TsnMultidropNetDevice>();
|
||||
net3->SetAttribute("DataRate", DataRateValue(DataRate("10Mb/s")));
|
||||
net3->SetAttribute("PLCALocalNodeId", UintegerValue(3));
|
||||
net3->SetAttribute("PLCANodeCount", UintegerValue(4));
|
||||
n3->AddDevice(net3);
|
||||
Names::Add("ES4#01", net3);
|
||||
|
||||
|
||||
//Create a 10Base-T1S Channel and attach it two the netDevices
|
||||
Ptr<TsnMultidropChannel> channel = CreateObject<TsnMultidropChannel>();
|
||||
net0->Attach(channel);
|
||||
net1->Attach(channel);
|
||||
net2->Attach(channel);
|
||||
net3->Attach(channel);
|
||||
|
||||
|
||||
//Allocate a Mac address
|
||||
net0->SetAddress(Mac48Address::Allocate());
|
||||
net1->SetAddress(Mac48Address::Allocate());
|
||||
net2->SetAddress(Mac48Address::Allocate());
|
||||
net3->SetAddress(Mac48Address::Allocate());
|
||||
|
||||
//Create and add eight FIFO on each net device
|
||||
for (int i=0; i<8; i++)
|
||||
{
|
||||
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net2->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net3->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
}
|
||||
|
||||
Ptr<Cbs> cbs = CreateObject<Cbs>();
|
||||
cbs->SetTsnNetDevice(net0);
|
||||
cbs->SetAttribute("IdleSlope", DataRateValue(DataRate("1300Kb/s")));
|
||||
cbs->SetAttribute("portTransmitRate", DataRateValue(DataRate("10Mb/s")));
|
||||
cbs->SetAttribute("MultidropMode", BooleanValue(true));
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>(), cbs);
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
|
||||
|
||||
//Add two GCL entry on net0 and start TAS
|
||||
net0->AddGclEntry(Time(MilliSeconds(10)), 2);
|
||||
net0->AddGclEntry(Time(MilliSeconds(4)), 1);
|
||||
net0->GetTas()->SetAttribute("GuardBandMode", EnumValue(Tas::MTU));
|
||||
net0->GetTas()->SetAttribute("MultidropMode", BooleanValue(true));
|
||||
net0->StartTas();
|
||||
|
||||
|
||||
//Application description
|
||||
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
|
||||
app0->Setup(net0);
|
||||
app0->SetAttribute("BurstSize", UintegerValue(2));
|
||||
app0->SetAttribute("PayloadSize", UintegerValue(1400));
|
||||
app0->SetAttribute("Period", TimeValue(Seconds(5)));
|
||||
app0->SetAttribute("VlanID", UintegerValue(1));
|
||||
app0->SetAttribute("PCP", UintegerValue(1));
|
||||
|
||||
n0->AddApplication(app0);
|
||||
app0->SetStartTime(Seconds(0));
|
||||
app0->SetStopTime(Seconds(10));
|
||||
|
||||
|
||||
Ptr<EthernetGenerator> app1 = CreateObject<EthernetGenerator>();
|
||||
app1->Setup(net0);
|
||||
app1->SetAttribute("BurstSize", UintegerValue(2));
|
||||
app1->SetAttribute("PayloadSize", UintegerValue(1400));
|
||||
app1->SetAttribute("Period", TimeValue(Seconds(5)));
|
||||
app1->SetAttribute("VlanID", UintegerValue(2));
|
||||
app1->SetAttribute("PCP", UintegerValue(0));
|
||||
|
||||
n0->AddApplication(app1);
|
||||
app1->SetStartTime(Seconds(0));
|
||||
app1->SetStopTime(Seconds(10));
|
||||
|
||||
//Callback to log pkt fifo entry time
|
||||
std::string context = Names::FindName(n0) + ":" + Names::FindName(net0);
|
||||
net0->TraceConnectWithoutContext("MacTx", MakeBoundCallback(&MacTxCallback, context));
|
||||
context = Names::FindName(n1) + ":" + Names::FindName(net1);
|
||||
net1->TraceConnectWithoutContext("MacTx", MakeBoundCallback(&MacTxCallback, context));
|
||||
context = Names::FindName(n2) + ":" + Names::FindName(net2);
|
||||
net2->TraceConnectWithoutContext("MacTx", MakeBoundCallback(&MacTxCallback, context));
|
||||
context = Names::FindName(n3) + ":" + Names::FindName(net3);
|
||||
net3->TraceConnectWithoutContext("MacTx", MakeBoundCallback(&MacTxCallback, context));
|
||||
|
||||
//Callback to display the packet latency
|
||||
net0->TraceConnectWithoutContext("Latency", MakeBoundCallback(&LatencyCallback, context));
|
||||
context = Names::FindName(n1) + ":" + Names::FindName(net1);
|
||||
net1->TraceConnectWithoutContext("Latency", MakeBoundCallback(&LatencyCallback, context));
|
||||
context = Names::FindName(n2) + ":" + Names::FindName(net2);
|
||||
net2->TraceConnectWithoutContext("Latency", MakeBoundCallback(&LatencyCallback, context));
|
||||
context = Names::FindName(n3) + ":" + Names::FindName(net3);
|
||||
net3->TraceConnectWithoutContext("Latency", MakeBoundCallback(&LatencyCallback, context));
|
||||
|
||||
|
||||
// net0->TraceConnectWithoutContext("PLCAState", MakeBoundCallback(&PLCAStateCallback, Names::FindName(net0)));
|
||||
// net1->TraceConnectWithoutContext("PLCAState", MakeBoundCallback(&PLCAStateCallback, Names::FindName(net1)));
|
||||
// net2->TraceConnectWithoutContext("PLCAState", MakeBoundCallback(&PLCAStateCallback, Names::FindName(net2)));
|
||||
// net3->TraceConnectWithoutContext("PLCAState", MakeBoundCallback(&PLCAStateCallback, Names::FindName(net3)));
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(MilliSeconds(20));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
274
contrib/tsn/examples/tsn-multidrop-withTAS.cc
Normal file
274
contrib/tsn/examples/tsn-multidrop-withTAS.cc
Normal file
@@ -0,0 +1,274 @@
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/applications-module.h"
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/drop-tail-queue.h"
|
||||
#include "ns3/timestamp-tag.h"
|
||||
|
||||
#include "ns3/tsn-multidrop-net-device.h"
|
||||
#include "ns3/tsn-multidrop-channel.h"
|
||||
#include "ns3/ethernet-generator.h"
|
||||
#include "ns3/ethernet-header2.h"
|
||||
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example of the use of tsn-net-device.cc tsn-multidrop-channel.cc on a network
|
||||
* composed of four end-stations connected by a 10Base-T1S with TAS on ES1 port
|
||||
* ES1 ====== ES2
|
||||
* ||
|
||||
* ||== ES3
|
||||
* ||
|
||||
* ||== ES4
|
||||
*/
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("Example");
|
||||
|
||||
|
||||
//A callback to log pkt fifo entry time
|
||||
static void
|
||||
MacTxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
Ptr<Packet> originalPacket = p->Copy();
|
||||
EthernetHeader2 ethHeader;
|
||||
originalPacket->RemoveHeader(ethHeader);
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << "(VID:" << ethHeader.GetVid() << ") entering the FIFO on the producer");
|
||||
}
|
||||
|
||||
//A callback to log the pkt latency
|
||||
static void
|
||||
LatencyCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
TimestampTag tag;
|
||||
if (!p->FindFirstMatchingByteTag(tag))
|
||||
{
|
||||
return;
|
||||
}
|
||||
Time arrival = Simulator::Now();
|
||||
Time latency = arrival - tag.GetTimestamp();
|
||||
|
||||
Ptr<Packet> originalPacket = p->Copy();
|
||||
EthernetHeader2 ethHeader;
|
||||
originalPacket->RemoveHeader(ethHeader);
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " received from " << ethHeader.GetSrc() << "(VID:" << ethHeader.GetVid() << ") with a latency=" << latency.GetNanoSeconds() <<"ns");
|
||||
}
|
||||
|
||||
//A callback to log the PLCA state
|
||||
static void
|
||||
PLCAStateCallback(std::string context, TsnMultidropNetDevice::PLCAState state)
|
||||
{
|
||||
std::string stateStr = "";
|
||||
if ( state == TsnMultidropNetDevice::PLCAState::DISABLE)
|
||||
{
|
||||
stateStr = "DISABLE";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::RECOVER)
|
||||
{
|
||||
stateStr = "RECOVER";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::RESYNC)
|
||||
{
|
||||
stateStr = "RESYNC";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::SEND_BEACON)
|
||||
{
|
||||
stateStr = "SEND_BEACON";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::SYNCING)
|
||||
{
|
||||
stateStr = "SYNCING";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::WAIT_TO)
|
||||
{
|
||||
stateStr = "WAIT_TO";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::COMMIT)
|
||||
{
|
||||
stateStr = "COMMIT";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::TRANSMIT)
|
||||
{
|
||||
stateStr = "TRANSMIT";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::BURST)
|
||||
{
|
||||
stateStr = "BURST";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::RECEIVE)
|
||||
{
|
||||
stateStr = "RECEIVE";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::YIELD)
|
||||
{
|
||||
stateStr = "YIELD";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::ABORT)
|
||||
{
|
||||
stateStr = "ABORT";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::NEXT_TX_OPPORTUNITY)
|
||||
{
|
||||
stateStr = "NEXT_TX_OPPORTUNITY";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::EARLY_RECEIVE)
|
||||
{
|
||||
stateStr = "EARLY_RECEIVE";
|
||||
}
|
||||
else
|
||||
{
|
||||
stateStr = "UNKNOWN_STATE";
|
||||
}
|
||||
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : PLCAState => " << stateStr);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
//Enable logging
|
||||
LogComponentEnable("Example", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("EthernetGenerator", LOG_LEVEL_INFO);
|
||||
// LogComponentEnable("TsnMultidropNetDevice", LOG_LEVEL_INFO);
|
||||
// LogComponentEnable("TsnMultidropChannel", LOG_LEVEL_INFO);
|
||||
|
||||
CommandLine cmd(__FILE__);
|
||||
cmd.Parse(argc, argv);
|
||||
|
||||
//Create four nodes
|
||||
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
|
||||
Names::Add("ES1", n0);
|
||||
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
|
||||
Names::Add("ES2", n1);
|
||||
Ptr<TsnNode> n2 = CreateObject<TsnNode>();
|
||||
Names::Add("ES3", n2);
|
||||
Ptr<TsnNode> n3 = CreateObject<TsnNode>();
|
||||
Names::Add("ES4", n3);
|
||||
|
||||
//Add perfect clock on each node
|
||||
n0->AddClock(CreateObject<Clock>());
|
||||
n1->AddClock(CreateObject<Clock>());
|
||||
n2->AddClock(CreateObject<Clock>());
|
||||
n3->AddClock(CreateObject<Clock>());
|
||||
|
||||
|
||||
//Create and add a netDevice to each node
|
||||
Ptr<TsnMultidropNetDevice> net0 = CreateObject<TsnMultidropNetDevice>();
|
||||
net0->SetAttribute("DataRate", DataRateValue(DataRate("10Mb/s")));
|
||||
net0->SetAttribute("PLCALocalNodeId", UintegerValue(0));
|
||||
net0->SetAttribute("PLCANodeCount", UintegerValue(4));
|
||||
// net0->SetAttribute("PLCAMaxBurstCount", UintegerValue(1));
|
||||
n0->AddDevice(net0);
|
||||
Names::Add("ES1#01", net0);
|
||||
Ptr<TsnMultidropNetDevice> net1 = CreateObject<TsnMultidropNetDevice>();
|
||||
net1->SetAttribute("DataRate", DataRateValue(DataRate("10Mb/s")));
|
||||
net1->SetAttribute("PLCALocalNodeId", UintegerValue(1));
|
||||
net1->SetAttribute("PLCANodeCount", UintegerValue(4));
|
||||
n1->AddDevice(net1);
|
||||
Names::Add("ES2#01", net1);
|
||||
Ptr<TsnMultidropNetDevice> net2 = CreateObject<TsnMultidropNetDevice>();
|
||||
net2->SetAttribute("DataRate", DataRateValue(DataRate("10Mb/s")));
|
||||
net2->SetAttribute("PLCALocalNodeId", UintegerValue(2));
|
||||
net2->SetAttribute("PLCANodeCount", UintegerValue(4));
|
||||
n2->AddDevice(net2);
|
||||
Names::Add("ES3#01", net2);
|
||||
Ptr<TsnMultidropNetDevice> net3 = CreateObject<TsnMultidropNetDevice>();
|
||||
net3->SetAttribute("DataRate", DataRateValue(DataRate("10Mb/s")));
|
||||
net3->SetAttribute("PLCALocalNodeId", UintegerValue(3));
|
||||
net3->SetAttribute("PLCANodeCount", UintegerValue(4));
|
||||
n3->AddDevice(net3);
|
||||
Names::Add("ES4#01", net3);
|
||||
|
||||
|
||||
//Create a 10Base-T1S Channel and attach it two the netDevices
|
||||
Ptr<TsnMultidropChannel> channel = CreateObject<TsnMultidropChannel>();
|
||||
net0->Attach(channel);
|
||||
net1->Attach(channel);
|
||||
net2->Attach(channel);
|
||||
net3->Attach(channel);
|
||||
|
||||
|
||||
//Allocate a Mac address
|
||||
net0->SetAddress(Mac48Address::Allocate());
|
||||
net1->SetAddress(Mac48Address::Allocate());
|
||||
net2->SetAddress(Mac48Address::Allocate());
|
||||
net3->SetAddress(Mac48Address::Allocate());
|
||||
|
||||
//Create and add eight FIFO on each net device
|
||||
for (int i=0; i<8; i++)
|
||||
{
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net2->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net3->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
}
|
||||
|
||||
//Add two GCL entry on net0 and start TAS
|
||||
net0->AddGclEntry(Time(MilliSeconds(2)), 2);
|
||||
net0->AddGclEntry(Time(MilliSeconds(4)), 1);
|
||||
net0->GetTas()->SetAttribute("GuardBandMode", EnumValue(Tas::MTU));
|
||||
net0->GetTas()->SetAttribute("MultidropMode", BooleanValue(true));
|
||||
net0->StartTas();
|
||||
|
||||
|
||||
//Application description
|
||||
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
|
||||
app0->Setup(net0);
|
||||
app0->SetAttribute("BurstSize", UintegerValue(2));
|
||||
app0->SetAttribute("PayloadSize", UintegerValue(1400));
|
||||
app0->SetAttribute("Period", TimeValue(Seconds(5)));
|
||||
app0->SetAttribute("VlanID", UintegerValue(1));
|
||||
app0->SetAttribute("PCP", UintegerValue(1));
|
||||
|
||||
n0->AddApplication(app0);
|
||||
app0->SetStartTime(Seconds(0));
|
||||
app0->SetStopTime(Seconds(10));
|
||||
|
||||
|
||||
Ptr<EthernetGenerator> app1 = CreateObject<EthernetGenerator>();
|
||||
app1->Setup(net0);
|
||||
app1->SetAttribute("BurstSize", UintegerValue(2));
|
||||
app1->SetAttribute("PayloadSize", UintegerValue(1400));
|
||||
app1->SetAttribute("Period", TimeValue(Seconds(5)));
|
||||
app1->SetAttribute("VlanID", UintegerValue(2));
|
||||
app1->SetAttribute("PCP", UintegerValue(0));
|
||||
|
||||
n0->AddApplication(app1);
|
||||
app1->SetStartTime(Seconds(0));
|
||||
app1->SetStopTime(Seconds(10));
|
||||
|
||||
//Callback to log pkt fifo entry time
|
||||
std::string context = Names::FindName(n0) + ":" + Names::FindName(net0);
|
||||
net0->TraceConnectWithoutContext("MacTx", MakeBoundCallback(&MacTxCallback, context));
|
||||
context = Names::FindName(n1) + ":" + Names::FindName(net1);
|
||||
net1->TraceConnectWithoutContext("MacTx", MakeBoundCallback(&MacTxCallback, context));
|
||||
context = Names::FindName(n2) + ":" + Names::FindName(net2);
|
||||
net2->TraceConnectWithoutContext("MacTx", MakeBoundCallback(&MacTxCallback, context));
|
||||
context = Names::FindName(n3) + ":" + Names::FindName(net3);
|
||||
net3->TraceConnectWithoutContext("MacTx", MakeBoundCallback(&MacTxCallback, context));
|
||||
|
||||
//Callback to display the packet latency
|
||||
net0->TraceConnectWithoutContext("Latency", MakeBoundCallback(&LatencyCallback, context));
|
||||
context = Names::FindName(n1) + ":" + Names::FindName(net1);
|
||||
net1->TraceConnectWithoutContext("Latency", MakeBoundCallback(&LatencyCallback, context));
|
||||
context = Names::FindName(n2) + ":" + Names::FindName(net2);
|
||||
net2->TraceConnectWithoutContext("Latency", MakeBoundCallback(&LatencyCallback, context));
|
||||
context = Names::FindName(n3) + ":" + Names::FindName(net3);
|
||||
net3->TraceConnectWithoutContext("Latency", MakeBoundCallback(&LatencyCallback, context));
|
||||
|
||||
|
||||
// net0->TraceConnectWithoutContext("PLCAState", MakeBoundCallback(&PLCAStateCallback, Names::FindName(net0)));
|
||||
// net1->TraceConnectWithoutContext("PLCAState", MakeBoundCallback(&PLCAStateCallback, Names::FindName(net1)));
|
||||
// net2->TraceConnectWithoutContext("PLCAState", MakeBoundCallback(&PLCAStateCallback, Names::FindName(net2)));
|
||||
// net3->TraceConnectWithoutContext("PLCAState", MakeBoundCallback(&PLCAStateCallback, Names::FindName(net3)));
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(MilliSeconds(8));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
254
contrib/tsn/examples/tsn-multidrop.cc
Normal file
254
contrib/tsn/examples/tsn-multidrop.cc
Normal file
@@ -0,0 +1,254 @@
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/applications-module.h"
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/drop-tail-queue.h"
|
||||
#include "ns3/timestamp-tag.h"
|
||||
|
||||
#include "ns3/tsn-multidrop-net-device.h"
|
||||
#include "ns3/tsn-multidrop-channel.h"
|
||||
#include "ns3/ethernet-generator.h"
|
||||
#include "ns3/ethernet-header2.h"
|
||||
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example of the use of tsn-net-device.cc tsn-multidrop-channel.cc on a network
|
||||
* composed of four end-stations connected by a 10Base-T1S
|
||||
* ES1 ====== ES2
|
||||
* ||
|
||||
* ||== ES3
|
||||
* ||
|
||||
* ||== ES4
|
||||
*/
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("Example");
|
||||
|
||||
|
||||
//A callback to log pkt fifo entry time
|
||||
static void
|
||||
MacTxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
Ptr<Packet> originalPacket = p->Copy();
|
||||
EthernetHeader2 ethHeader;
|
||||
originalPacket->RemoveHeader(ethHeader);
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << "(VID:" << ethHeader.GetVid() << ") entering the FIFO on the producer");
|
||||
}
|
||||
|
||||
//A callback to log the pkt latency
|
||||
static void
|
||||
LatencyCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
TimestampTag tag;
|
||||
if (!p->FindFirstMatchingByteTag(tag))
|
||||
{
|
||||
return;
|
||||
}
|
||||
Time arrival = Simulator::Now();
|
||||
Time latency = arrival - tag.GetTimestamp();
|
||||
|
||||
Ptr<Packet> originalPacket = p->Copy();
|
||||
EthernetHeader2 ethHeader;
|
||||
originalPacket->RemoveHeader(ethHeader);
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " received from " << ethHeader.GetSrc() << "(VID:" << ethHeader.GetVid() << ") with a latency=" << latency.GetNanoSeconds() <<"ns");
|
||||
}
|
||||
|
||||
//A callback to log the PLCA state
|
||||
static void
|
||||
PLCAStateCallback(std::string context, TsnMultidropNetDevice::PLCAState state)
|
||||
{
|
||||
std::string stateStr = "";
|
||||
if ( state == TsnMultidropNetDevice::PLCAState::DISABLE)
|
||||
{
|
||||
stateStr = "DISABLE";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::RECOVER)
|
||||
{
|
||||
stateStr = "RECOVER";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::RESYNC)
|
||||
{
|
||||
stateStr = "RESYNC";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::SEND_BEACON)
|
||||
{
|
||||
stateStr = "SEND_BEACON";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::SYNCING)
|
||||
{
|
||||
stateStr = "SYNCING";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::WAIT_TO)
|
||||
{
|
||||
stateStr = "WAIT_TO";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::COMMIT)
|
||||
{
|
||||
stateStr = "COMMIT";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::TRANSMIT)
|
||||
{
|
||||
stateStr = "TRANSMIT";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::BURST)
|
||||
{
|
||||
stateStr = "BURST";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::RECEIVE)
|
||||
{
|
||||
stateStr = "RECEIVE";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::YIELD)
|
||||
{
|
||||
stateStr = "YIELD";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::ABORT)
|
||||
{
|
||||
stateStr = "ABORT";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::NEXT_TX_OPPORTUNITY)
|
||||
{
|
||||
stateStr = "NEXT_TX_OPPORTUNITY";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::EARLY_RECEIVE)
|
||||
{
|
||||
stateStr = "EARLY_RECEIVE";
|
||||
}
|
||||
else
|
||||
{
|
||||
stateStr = "UNKNOWN_STATE";
|
||||
}
|
||||
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : PLCAState => " << stateStr);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
//Enable logging
|
||||
LogComponentEnable("Example", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("EthernetGenerator", LOG_LEVEL_INFO);
|
||||
// LogComponentEnable("TsnMultidropNetDevice", LOG_LEVEL_INFO);
|
||||
// LogComponentEnable("TsnMultidropChannel", LOG_LEVEL_INFO);
|
||||
|
||||
CommandLine cmd(__FILE__);
|
||||
cmd.Parse(argc, argv);
|
||||
|
||||
//Create four nodes
|
||||
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
|
||||
Names::Add("ES1", n0);
|
||||
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
|
||||
Names::Add("ES2", n1);
|
||||
Ptr<TsnNode> n2 = CreateObject<TsnNode>();
|
||||
Names::Add("ES3", n2);
|
||||
Ptr<TsnNode> n3 = CreateObject<TsnNode>();
|
||||
Names::Add("ES4", n3);
|
||||
|
||||
|
||||
//Create and add a netDevice to each node
|
||||
Ptr<TsnMultidropNetDevice> net0 = CreateObject<TsnMultidropNetDevice>();
|
||||
net0->SetAttribute("PLCALocalNodeId", UintegerValue(0));
|
||||
net0->SetAttribute("PLCANodeCount", UintegerValue(4));
|
||||
// net0->SetAttribute("PLCAMaxBurstCount", UintegerValue(1));
|
||||
n0->AddDevice(net0);
|
||||
Names::Add("ES1#01", net0);
|
||||
Ptr<TsnMultidropNetDevice> net1 = CreateObject<TsnMultidropNetDevice>();
|
||||
net1->SetAttribute("PLCALocalNodeId", UintegerValue(1));
|
||||
net1->SetAttribute("PLCANodeCount", UintegerValue(4));
|
||||
n1->AddDevice(net1);
|
||||
Names::Add("ES2#01", net1);
|
||||
Ptr<TsnMultidropNetDevice> net2 = CreateObject<TsnMultidropNetDevice>();
|
||||
net2->SetAttribute("PLCALocalNodeId", UintegerValue(2));
|
||||
net2->SetAttribute("PLCANodeCount", UintegerValue(4));
|
||||
n2->AddDevice(net2);
|
||||
Names::Add("ES3#01", net2);
|
||||
Ptr<TsnMultidropNetDevice> net3 = CreateObject<TsnMultidropNetDevice>();
|
||||
net3->SetAttribute("PLCALocalNodeId", UintegerValue(3));
|
||||
net3->SetAttribute("PLCANodeCount", UintegerValue(4));
|
||||
n3->AddDevice(net3);
|
||||
Names::Add("ES4#01", net3);
|
||||
|
||||
|
||||
//Create a 10Base-T1S Channel and attach it two the netDevices
|
||||
Ptr<TsnMultidropChannel> channel = CreateObject<TsnMultidropChannel>();
|
||||
net0->Attach(channel);
|
||||
net1->Attach(channel);
|
||||
net2->Attach(channel);
|
||||
net3->Attach(channel);
|
||||
|
||||
|
||||
//Allocate a Mac address and create a FIFO (for the output port)
|
||||
//for each netDevice.
|
||||
net0->SetAddress(Mac48Address::Allocate());
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
|
||||
net1->SetAddress(Mac48Address::Allocate());
|
||||
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
|
||||
net2->SetAddress(Mac48Address::Allocate());
|
||||
net2->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
|
||||
net3->SetAddress(Mac48Address::Allocate());
|
||||
net3->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
|
||||
|
||||
//Application description
|
||||
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
|
||||
app0->Setup(net0);
|
||||
app0->SetAttribute("BurstSize", UintegerValue(2));
|
||||
app0->SetAttribute("PayloadSize", UintegerValue(1400));
|
||||
app0->SetAttribute("Period", TimeValue(Seconds(5)));
|
||||
app0->SetAttribute("VlanID", UintegerValue(1));
|
||||
|
||||
n0->AddApplication(app0);
|
||||
app0->SetStartTime(Seconds(0));
|
||||
app0->SetStopTime(Seconds(10));
|
||||
|
||||
|
||||
Ptr<EthernetGenerator> app1 = CreateObject<EthernetGenerator>();
|
||||
app1->Setup(net1);
|
||||
app1->SetAttribute("BurstSize", UintegerValue(2));
|
||||
app1->SetAttribute("PayloadSize", UintegerValue(1400));
|
||||
app1->SetAttribute("Period", TimeValue(Seconds(5)));
|
||||
app1->SetAttribute("VlanID", UintegerValue(2));
|
||||
|
||||
n1->AddApplication(app1);
|
||||
app1->SetStartTime(Seconds(0));
|
||||
app1->SetStopTime(Seconds(10));
|
||||
|
||||
//Callback to log pkt fifo entry time
|
||||
std::string context = Names::FindName(n0) + ":" + Names::FindName(net0);
|
||||
net0->TraceConnectWithoutContext("MacTx", MakeBoundCallback(&MacTxCallback, context));
|
||||
context = Names::FindName(n1) + ":" + Names::FindName(net1);
|
||||
net1->TraceConnectWithoutContext("MacTx", MakeBoundCallback(&MacTxCallback, context));
|
||||
context = Names::FindName(n2) + ":" + Names::FindName(net2);
|
||||
net2->TraceConnectWithoutContext("MacTx", MakeBoundCallback(&MacTxCallback, context));
|
||||
context = Names::FindName(n3) + ":" + Names::FindName(net3);
|
||||
net3->TraceConnectWithoutContext("MacTx", MakeBoundCallback(&MacTxCallback, context));
|
||||
|
||||
//Callback to display the packet latency
|
||||
net0->TraceConnectWithoutContext("Latency", MakeBoundCallback(&LatencyCallback, context));
|
||||
context = Names::FindName(n1) + ":" + Names::FindName(net1);
|
||||
net1->TraceConnectWithoutContext("Latency", MakeBoundCallback(&LatencyCallback, context));
|
||||
context = Names::FindName(n2) + ":" + Names::FindName(net2);
|
||||
net2->TraceConnectWithoutContext("Latency", MakeBoundCallback(&LatencyCallback, context));
|
||||
context = Names::FindName(n3) + ":" + Names::FindName(net3);
|
||||
net3->TraceConnectWithoutContext("Latency", MakeBoundCallback(&LatencyCallback, context));
|
||||
|
||||
|
||||
net0->TraceConnectWithoutContext("PLCAState", MakeBoundCallback(&PLCAStateCallback, Names::FindName(net0)));
|
||||
net1->TraceConnectWithoutContext("PLCAState", MakeBoundCallback(&PLCAStateCallback, Names::FindName(net1)));
|
||||
net2->TraceConnectWithoutContext("PLCAState", MakeBoundCallback(&PLCAStateCallback, Names::FindName(net2)));
|
||||
net3->TraceConnectWithoutContext("PLCAState", MakeBoundCallback(&PLCAStateCallback, Names::FindName(net3)));
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(MilliSeconds(5));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
119
contrib/tsn/examples/tsn-point2point-withCBS.cc
Normal file
119
contrib/tsn/examples/tsn-point2point-withCBS.cc
Normal file
@@ -0,0 +1,119 @@
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/applications-module.h"
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/drop-tail-queue.h"
|
||||
|
||||
#include "ns3/tsn-net-device.h"
|
||||
#include "ns3/cbs.h"
|
||||
#include "ns3/ethernet-channel.h"
|
||||
#include "ns3/ethernet-generator.h"
|
||||
#include "ns3/ethernet-header2.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example of the use of tsn-node.cc tsn-net-device.cc ethernet-channel.cc
|
||||
* on a network composed of two end-stations connected by a 100Mb/s
|
||||
* full duplex link with CBS on ES1 port
|
||||
* ES1 ====== ES2
|
||||
*/
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("Example");
|
||||
|
||||
//A callback to log the pkt reception
|
||||
static void
|
||||
MacRxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " received !");
|
||||
}
|
||||
|
||||
//A callback to log the pkt emission
|
||||
static void
|
||||
PhyTxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " begin transmission !");
|
||||
}
|
||||
|
||||
//A callback to log the credit value
|
||||
static void
|
||||
CbsCallback(std::string context, double credit)
|
||||
{
|
||||
Time t = Simulator::Now();
|
||||
NS_LOG_INFO("FIFO:" << context << " : At "<< t.GetNanoSeconds() <<" credit=" << credit);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
//Enable logging
|
||||
LogComponentEnable("Example", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("EthernetGenerator", LOG_LEVEL_INFO);
|
||||
|
||||
CommandLine cmd(__FILE__);
|
||||
cmd.Parse(argc, argv);
|
||||
|
||||
//Create two nodes
|
||||
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
|
||||
Names::Add("ES1", n0);
|
||||
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
|
||||
Names::Add("ES2", n1);
|
||||
|
||||
//Create and add a netDevice to each node
|
||||
Ptr<TsnNetDevice> net0 = CreateObject<TsnNetDevice>();
|
||||
net0->SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
|
||||
n0->AddDevice(net0);
|
||||
Names::Add("ES1#01", net0);
|
||||
Ptr<TsnNetDevice> net1 = CreateObject<TsnNetDevice>();
|
||||
net1->SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
|
||||
n1->AddDevice(net1);
|
||||
Names::Add("ES2#01", net1);
|
||||
|
||||
//Create a Ethernet Channel and attach it two the two netDevices
|
||||
Ptr<EthernetChannel> channel = CreateObject<EthernetChannel>();
|
||||
net0->Attach(channel);
|
||||
net1->Attach(channel);
|
||||
|
||||
//Allocate a Mac address
|
||||
net0->SetAddress(Mac48Address::Allocate());
|
||||
net1->SetAddress(Mac48Address::Allocate());
|
||||
|
||||
//Create and add a CBS shaper and a FIFO on net0 only fifo.
|
||||
Ptr<Cbs> cbs = CreateObject<Cbs>();
|
||||
cbs->SetTsnNetDevice(net0);
|
||||
Names::Add(Names::FindName(net0) + "-" + "0", cbs); //NetDeviceName-FifoNumber
|
||||
cbs->SetAttribute("IdleSlope", DataRateValue(DataRate("5Mb/s")));
|
||||
cbs->SetAttribute("portTransmitRate", DataRateValue(DataRate("100Mb/s")));
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>(), cbs);
|
||||
//Create and add a FIFO on net1
|
||||
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
|
||||
//Application description
|
||||
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
|
||||
app0->Setup(net0);
|
||||
app0->SetAttribute("BurstSize", UintegerValue(5));
|
||||
app0->SetAttribute("PayloadSize", UintegerValue(1400));
|
||||
app0->SetAttribute("Period", TimeValue(Seconds(5)));
|
||||
|
||||
n0->AddApplication(app0);
|
||||
app0->SetStartTime(Seconds(0));
|
||||
app0->SetStopTime(Seconds(4));
|
||||
|
||||
//Callback to display the packet transmitted and received log
|
||||
net0->TraceConnectWithoutContext("PhyTxBegin", MakeBoundCallback(&PhyTxCallback, Names::FindName(n0) + ":" + Names::FindName(net0)));
|
||||
net1->TraceConnectWithoutContext("MacRx", MakeBoundCallback(&MacRxCallback, Names::FindName(n1) + ":" + Names::FindName(net1)));
|
||||
//Callback to display the credit update log
|
||||
cbs->TraceConnectWithoutContext("Credit", MakeBoundCallback(&CbsCallback, Names::FindName(cbs)));
|
||||
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(Seconds(10));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
127
contrib/tsn/examples/tsn-point2point-withGPTP-Multidomain.cc
Normal file
127
contrib/tsn/examples/tsn-point2point-withGPTP-Multidomain.cc
Normal file
@@ -0,0 +1,127 @@
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/applications-module.h"
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/drop-tail-queue.h"
|
||||
|
||||
#include "ns3/tsn-node.h"
|
||||
#include "ns3/tsn-net-device.h"
|
||||
#include "ns3/ethernet-channel.h"
|
||||
#include "ns3/clock.h"
|
||||
#include "ns3/clock-constant-drift.h"
|
||||
#include "ns3/gPTP.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example of the use of gPTP with two domain on a network composed of two
|
||||
* end-stations connected by a 1Gb/s full duplex link.
|
||||
* ES1 is the GPTP Grandmaster for the two domains.
|
||||
* Is this example, all the clock on the same node are slaved on the main clock
|
||||
* ES1 ====== ES2
|
||||
*/
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("Example");
|
||||
|
||||
static void
|
||||
PdelayCallback(std::string context, Ptr<TsnNetDevice> net, double pdelay)
|
||||
{
|
||||
NS_LOG_INFO("[GPTP] At " << Simulator::Now() << " on "<< context << "/" << Names::FindName(net) << " computed pdelay = " << pdelay);
|
||||
}
|
||||
|
||||
static void
|
||||
ClockAfterCorrectionCallback(std::string context, Time clockValue)
|
||||
{
|
||||
NS_LOG_INFO("[GPTP] At " << Simulator::Now() << " on "<< context << " clock value after correction = " << clockValue.GetNanoSeconds() << "ns (error = "<< (Simulator::Now()-clockValue).GetNanoSeconds() << "ns)");
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
//Enable logging
|
||||
LogComponentEnable("Example", LOG_LEVEL_INFO);
|
||||
|
||||
CommandLine cmd(__FILE__);
|
||||
cmd.Parse(argc, argv);
|
||||
|
||||
//Create two nodes
|
||||
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
|
||||
Names::Add("ES1", n0);
|
||||
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
|
||||
Names::Add("ES2", n1);
|
||||
|
||||
|
||||
//Create and add clock to TsnNode
|
||||
Ptr<Clock> c0 = CreateObject<Clock>(); //Perfect clock
|
||||
n0->SetMainClock(c0);
|
||||
|
||||
Ptr<ConstantDriftClock> c1 = CreateObject<ConstantDriftClock>();
|
||||
c1->SetAttribute("InitialOffset", TimeValue(Seconds(1)));
|
||||
c1->SetAttribute("DriftRate", DoubleValue(10));
|
||||
c1->SetAttribute("Granularity", TimeValue(NanoSeconds(10)));
|
||||
n1->SetMainClock(c1);
|
||||
|
||||
//Create and add a netDevice to each node
|
||||
Ptr<TsnNetDevice> net0 = CreateObject<TsnNetDevice>();
|
||||
net0->SetAttribute("DataRate", DataRateValue(DataRate("1Gb/s")));
|
||||
n0->AddDevice(net0);
|
||||
Names::Add("ES1#01", net0);
|
||||
Ptr<TsnNetDevice> net1 = CreateObject<TsnNetDevice>();
|
||||
net1->SetAttribute("DataRate", DataRateValue(DataRate("1Gb/s")));
|
||||
n1->AddDevice(net1);
|
||||
Names::Add("ES2#01", net1);
|
||||
|
||||
//Create a Ethernet Channel and attach it two the two netDevices
|
||||
Ptr<EthernetChannel> channel = CreateObject<EthernetChannel>();
|
||||
channel->SetAttribute("Delay", TimeValue(Time(NanoSeconds(200))));
|
||||
net0->Attach(channel);
|
||||
net1->Attach(channel);
|
||||
|
||||
//Allocate a Mac address
|
||||
net0->SetAddress(Mac48Address::Allocate());
|
||||
net1->SetAddress(Mac48Address::Allocate());
|
||||
|
||||
//Add two fifo per netdevice.
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
|
||||
//Add and configure GPTP
|
||||
Ptr<GPTP> gPTP0 = CreateObject<GPTP>();
|
||||
gPTP0->SetNode(n0);
|
||||
gPTP0->SetMainClock(c0);
|
||||
gPTP0->AddDomain(0);
|
||||
gPTP0->AddDomain(4);
|
||||
gPTP0->AddPort(net0, GPTP::MASTER, 0);
|
||||
gPTP0->AddPort(net0, GPTP::MASTER, 4);
|
||||
gPTP0->SetAttribute("SyncInterval", TimeValue(Seconds(0.125))); //This line is not mandatory because 0.125s is the default value
|
||||
gPTP0->SetAttribute("PdelayInterval", TimeValue(Seconds(1))); //This line is not mandatory because 1s is the default value
|
||||
gPTP0->SetAttribute("Priority", UintegerValue(1));
|
||||
n0->AddApplication(gPTP0);
|
||||
gPTP0->SetStartTime(Seconds(0));
|
||||
|
||||
Ptr<GPTP> gPTP1 = CreateObject<GPTP>();
|
||||
gPTP1->SetNode(n1);
|
||||
gPTP1->SetMainClock(c1);
|
||||
gPTP1->AddDomain(0);
|
||||
gPTP1->AddDomain(4);
|
||||
gPTP1->AddPort(net1, GPTP::SLAVE, 0);
|
||||
gPTP1->AddPort(net1, GPTP::SLAVE, 4);
|
||||
gPTP1->SetAttribute("Priority", UintegerValue(1));
|
||||
n1->AddApplication(gPTP1);
|
||||
gPTP1->SetStartTime(Seconds(0));
|
||||
|
||||
//Callback to displa information about GPTP execution
|
||||
gPTP1->TraceConnectWithoutContext("Pdelay", MakeBoundCallback(&PdelayCallback, Names::FindName(n1)));
|
||||
gPTP1->TraceConnectWithoutContext("ClockAfterCorrection", MakeBoundCallback(&ClockAfterCorrectionCallback, Names::FindName(n1)));
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(Seconds(3));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/applications-module.h"
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/drop-tail-queue.h"
|
||||
|
||||
#include "ns3/tsn-node.h"
|
||||
#include "ns3/tsn-net-device.h"
|
||||
#include "ns3/ethernet-channel.h"
|
||||
#include "ns3/clock.h"
|
||||
#include "ns3/clock-fix-precision.h"
|
||||
#include "ns3/gPTP.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example of the use of gPTP on a network composed of two end-stations
|
||||
* connected by a 1Gb/s full duplex link. ES1 is the GPTP Grandmaster.
|
||||
* This exemple use fix precision clock (non realistic clock made for
|
||||
* research purpose)
|
||||
* ES1 ====== ES2
|
||||
*/
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("Example");
|
||||
|
||||
static void
|
||||
PdelayCallback(std::string context, Ptr<TsnNetDevice> net, double pdelay)
|
||||
{
|
||||
NS_LOG_INFO("[GPTP] At " << Simulator::Now() << " on "<< context << "/" << Names::FindName(net) << " computed pdelay = " << pdelay);
|
||||
}
|
||||
|
||||
static void
|
||||
ClockAfterCorrectionCallback(std::string context, Ptr<Clock> gmClock, Time clockValue)
|
||||
{
|
||||
NS_LOG_INFO("[GPTP] At " << Simulator::Now() << " on "<< context << " clock value after correction = " << clockValue.GetNanoSeconds() << "ns (error = "<< (gmClock->GetLocalTime()-clockValue).GetNanoSeconds() << "ns)");
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
//Enable logging
|
||||
LogComponentEnable("Example", LOG_LEVEL_INFO);
|
||||
// LogComponentEnable("GPTP", LOG_LEVEL_INFO);
|
||||
|
||||
CommandLine cmd(__FILE__);
|
||||
cmd.Parse(argc, argv);
|
||||
|
||||
//Create two nodes
|
||||
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
|
||||
Names::Add("ES1", n0);
|
||||
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
|
||||
Names::Add("ES2", n1);
|
||||
|
||||
|
||||
//Create and add clock to TsnNode
|
||||
Ptr<Clock> c0 = CreateObject<Clock>(); //Perfect clock
|
||||
n0->SetMainClock(c0);
|
||||
|
||||
Ptr<FixPrecisionClock> c1 = CreateObject<FixPrecisionClock>();
|
||||
c1->SetAttribute("Precision", TimeValue(NanoSeconds(100)));
|
||||
c1->SetRefClock(c0); //Set GM clock as reference
|
||||
n1->SetMainClock(c1);
|
||||
|
||||
//Create and add a netDevice to each node
|
||||
Ptr<TsnNetDevice> net0 = CreateObject<TsnNetDevice>();
|
||||
net0->SetAttribute("DataRate", DataRateValue(DataRate("1Gb/s")));
|
||||
n0->AddDevice(net0);
|
||||
Names::Add("ES1#01", net0);
|
||||
Ptr<TsnNetDevice> net1 = CreateObject<TsnNetDevice>();
|
||||
net1->SetAttribute("DataRate", DataRateValue(DataRate("1Gb/s")));
|
||||
n1->AddDevice(net1);
|
||||
Names::Add("ES2#01", net1);
|
||||
|
||||
//Create a Ethernet Channel and attach it two the two netDevices
|
||||
Ptr<EthernetChannel> channel = CreateObject<EthernetChannel>();
|
||||
channel->SetAttribute("Delay", TimeValue(Time(NanoSeconds(200))));
|
||||
net0->Attach(channel);
|
||||
net1->Attach(channel);
|
||||
|
||||
//Allocate a Mac address
|
||||
net0->SetAddress(Mac48Address::Allocate());
|
||||
net1->SetAddress(Mac48Address::Allocate());
|
||||
|
||||
//Add two fifo per netdevice.
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
|
||||
//Add and configure GPTP
|
||||
Ptr<GPTP> gPTP0 = CreateObject<GPTP>();
|
||||
gPTP0->SetNode(n0);
|
||||
gPTP0->SetMainClock(c0);
|
||||
gPTP0->AddDomain(0);
|
||||
gPTP0->AddPort(net0, GPTP::MASTER, 0);
|
||||
gPTP0->SetAttribute("SyncInterval", TimeValue(Seconds(0.125))); //This line is not mandatory because 0.125s is the default value
|
||||
gPTP0->SetAttribute("PdelayInterval", TimeValue(Seconds(1))); //This line is not mandatory because 1s is the default value
|
||||
gPTP0->SetAttribute("Priority", UintegerValue(1));
|
||||
n0->AddApplication(gPTP0);
|
||||
gPTP0->SetStartTime(Seconds(0));
|
||||
|
||||
Ptr<GPTP> gPTP1 = CreateObject<GPTP>();
|
||||
gPTP1->SetNode(n1);
|
||||
gPTP1->SetMainClock(c1);
|
||||
gPTP1->AddDomain(0, c1);
|
||||
gPTP1->AddPort(net1, GPTP::SLAVE, 0);
|
||||
gPTP1->SetAttribute("Priority", UintegerValue(1));
|
||||
n1->AddApplication(gPTP1);
|
||||
gPTP1->SetStartTime(Seconds(0));
|
||||
|
||||
//Callback to displa information about GPTP execution
|
||||
gPTP1->TraceConnectWithoutContext("Pdelay", MakeBoundCallback(&PdelayCallback, Names::FindName(n1)));
|
||||
gPTP1->TraceConnectWithoutContext("ClockAfterCorrection", MakeBoundCallback(&ClockAfterCorrectionCallback, Names::FindName(n1), c0));
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(Seconds(5));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
121
contrib/tsn/examples/tsn-point2point-withGPTP.cc
Normal file
121
contrib/tsn/examples/tsn-point2point-withGPTP.cc
Normal file
@@ -0,0 +1,121 @@
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/applications-module.h"
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/drop-tail-queue.h"
|
||||
|
||||
#include "ns3/tsn-node.h"
|
||||
#include "ns3/tsn-net-device.h"
|
||||
#include "ns3/ethernet-channel.h"
|
||||
#include "ns3/clock.h"
|
||||
#include "ns3/clock-constant-drift.h"
|
||||
#include "ns3/gPTP.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example of the use of gPTP on a network composed of two end-stations
|
||||
* connected by a 1Gb/s full duplex link. ES1 is the GPTP Grandmaster.
|
||||
* ES1 ====== ES2
|
||||
*/
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("Example");
|
||||
|
||||
static void
|
||||
PdelayCallback(std::string context, Ptr<TsnNetDevice> net, double pdelay)
|
||||
{
|
||||
NS_LOG_INFO("[GPTP] At " << Simulator::Now() << " on "<< context << "/" << Names::FindName(net) << " computed pdelay = " << pdelay);
|
||||
}
|
||||
|
||||
static void
|
||||
ClockAfterCorrectionCallback(std::string context, Time clockValue)
|
||||
{
|
||||
NS_LOG_INFO("[GPTP] At " << Simulator::Now() << " on "<< context << " clock value after correction = " << clockValue.GetNanoSeconds() << "ns (error = "<< (Simulator::Now()-clockValue).GetNanoSeconds() << "ns)");
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
//Enable logging
|
||||
LogComponentEnable("Example", LOG_LEVEL_INFO);
|
||||
|
||||
CommandLine cmd(__FILE__);
|
||||
cmd.Parse(argc, argv);
|
||||
|
||||
//Create two nodes
|
||||
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
|
||||
Names::Add("ES1", n0);
|
||||
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
|
||||
Names::Add("ES2", n1);
|
||||
|
||||
|
||||
//Create and add clock to TsnNode
|
||||
Ptr<Clock> c0 = CreateObject<Clock>(); //Perfect clock
|
||||
n0->SetMainClock(c0);
|
||||
|
||||
Ptr<ConstantDriftClock> c1 = CreateObject<ConstantDriftClock>();
|
||||
c1->SetAttribute("InitialOffset", TimeValue(Seconds(1)));
|
||||
c1->SetAttribute("DriftRate", DoubleValue(10));
|
||||
c1->SetAttribute("Granularity", TimeValue(NanoSeconds(10)));
|
||||
n1->SetMainClock(c1);
|
||||
|
||||
//Create and add a netDevice to each node
|
||||
Ptr<TsnNetDevice> net0 = CreateObject<TsnNetDevice>();
|
||||
net0->SetAttribute("DataRate", DataRateValue(DataRate("1Gb/s")));
|
||||
n0->AddDevice(net0);
|
||||
Names::Add("ES1#01", net0);
|
||||
Ptr<TsnNetDevice> net1 = CreateObject<TsnNetDevice>();
|
||||
net1->SetAttribute("DataRate", DataRateValue(DataRate("1Gb/s")));
|
||||
n1->AddDevice(net1);
|
||||
Names::Add("ES2#01", net1);
|
||||
|
||||
//Create a Ethernet Channel and attach it two the two netDevices
|
||||
Ptr<EthernetChannel> channel = CreateObject<EthernetChannel>();
|
||||
channel->SetAttribute("Delay", TimeValue(Time(NanoSeconds(200))));
|
||||
net0->Attach(channel);
|
||||
net1->Attach(channel);
|
||||
|
||||
//Allocate a Mac address
|
||||
net0->SetAddress(Mac48Address::Allocate());
|
||||
net1->SetAddress(Mac48Address::Allocate());
|
||||
|
||||
//Add two fifo per netdevice.
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
|
||||
//Add and configure GPTP
|
||||
Ptr<GPTP> gPTP0 = CreateObject<GPTP>();
|
||||
gPTP0->SetNode(n0);
|
||||
gPTP0->SetMainClock(c0);
|
||||
gPTP0->AddDomain(0);
|
||||
gPTP0->AddPort(net0, GPTP::MASTER, 0);
|
||||
gPTP0->SetAttribute("SyncInterval", TimeValue(Seconds(0.125))); //This line is not mandatory because 0.125s is the default value
|
||||
gPTP0->SetAttribute("PdelayInterval", TimeValue(Seconds(1))); //This line is not mandatory because 1s is the default value
|
||||
gPTP0->SetAttribute("Priority", UintegerValue(1));
|
||||
n0->AddApplication(gPTP0);
|
||||
gPTP0->SetStartTime(Seconds(0));
|
||||
|
||||
Ptr<GPTP> gPTP1 = CreateObject<GPTP>();
|
||||
gPTP1->SetNode(n1);
|
||||
gPTP1->SetMainClock(c1);
|
||||
gPTP1->AddDomain(0);
|
||||
gPTP1->AddPort(net1, GPTP::SLAVE, 0);
|
||||
gPTP1->SetAttribute("Priority", UintegerValue(1));
|
||||
n1->AddApplication(gPTP1);
|
||||
gPTP1->SetStartTime(Seconds(0));
|
||||
|
||||
//Callback to displa information about GPTP execution
|
||||
gPTP1->TraceConnectWithoutContext("Pdelay", MakeBoundCallback(&PdelayCallback, Names::FindName(n1)));
|
||||
gPTP1->TraceConnectWithoutContext("ClockAfterCorrection", MakeBoundCallback(&ClockAfterCorrectionCallback, Names::FindName(n1)));
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(Seconds(3));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
142
contrib/tsn/examples/tsn-point2point-withPSFP-FlowMeter.cc
Normal file
142
contrib/tsn/examples/tsn-point2point-withPSFP-FlowMeter.cc
Normal file
@@ -0,0 +1,142 @@
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/applications-module.h"
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/drop-tail-queue.h"
|
||||
|
||||
#include "ns3/tsn-net-device.h"
|
||||
#include "ns3/ethernet-channel.h"
|
||||
#include "ns3/ethernet-generator.h"
|
||||
#include "ns3/ethernet-header2.h"
|
||||
#include "ns3/stream-identification-function-null.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example of the use of tsn-node.cc tsn-net-device.cc ethernet-channel.cc
|
||||
* on a network composed of two end-stations connected by a 100Mb/s
|
||||
* full duplex link
|
||||
* ES1 ====== ES2
|
||||
*/
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("Example");
|
||||
|
||||
//A callback to log the pkt transmission
|
||||
static void
|
||||
MacTxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " entered the transmission FIFO !");
|
||||
}
|
||||
|
||||
//A callback to log the pkt reception
|
||||
static void
|
||||
MacRxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " received !");
|
||||
}
|
||||
|
||||
//Callbacks to log pkt drop
|
||||
static void
|
||||
MaxSDUSizeFilterDrop(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
NS_LOG_INFO(context << " : Packet #"<< p->GetUid() <<" was dropped by MaxSDUSizeFilter");
|
||||
}
|
||||
|
||||
static void
|
||||
REDFrameDrop(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
NS_LOG_INFO(context << " : Packet #"<< p->GetUid() <<" was dropped by Flow Meter");
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
//Enable logging
|
||||
LogComponentEnable("Example", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("TsnNetDevice", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("StreamFilterInstance", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("FlowMeterInstance", LOG_LEVEL_INFO);
|
||||
|
||||
CommandLine cmd(__FILE__);
|
||||
cmd.Parse(argc, argv);
|
||||
|
||||
//Create two nodes
|
||||
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
|
||||
Names::Add("ES1", n0);
|
||||
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
|
||||
Names::Add("ES2", n1);
|
||||
|
||||
//Create and add a netDevice to each node
|
||||
Ptr<TsnNetDevice> net0 = CreateObject<TsnNetDevice>();
|
||||
net0->SetAttribute("DataRate", DataRateValue(DataRate("1Gb/s")));
|
||||
n0->AddDevice(net0);
|
||||
Names::Add("ES1#01", net0);
|
||||
Ptr<TsnNetDevice> net1 = CreateObject<TsnNetDevice>();
|
||||
net1->SetAttribute("DataRate", DataRateValue(DataRate("1Gb/s")));
|
||||
n1->AddDevice(net1);
|
||||
Names::Add("ES2#01", net1);
|
||||
|
||||
//Create a Ethernet Channel and attach it two the two netDevices
|
||||
Ptr<EthernetChannel> channel = CreateObject<EthernetChannel>();
|
||||
net0->Attach(channel);
|
||||
net1->Attach(channel);
|
||||
|
||||
//Allocate a Mac address and create a FIFO (for the output port)
|
||||
//for each netDevice.
|
||||
net0->SetAddress(Mac48Address::Allocate());
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
|
||||
net1->SetAddress(Mac48Address::Allocate());
|
||||
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
|
||||
//Stream identification
|
||||
Ptr<NullStreamIdentificationFunction> sif0 = CreateObject<NullStreamIdentificationFunction>();
|
||||
uint16_t StreamHandle = 10;
|
||||
sif0->SetAttribute("VlanID", UintegerValue(100));
|
||||
sif0->SetAttribute("Address", AddressValue(Mac48Address("ff:ff:ff:ff:ff:ff")));
|
||||
n1->AddStreamIdentificationFunction(StreamHandle, sif0, {net1}, {}, {}, {});
|
||||
|
||||
//PSFP configuration
|
||||
Ptr<StreamFilterInstance> sfi0 = CreateObject<StreamFilterInstance>();
|
||||
sfi0->SetAttribute("StreamHandle", IntegerValue(StreamHandle));
|
||||
sfi0->SetAttribute("Priority", IntegerValue(-1)); //-1 = wildcard (like in PSFP MIB)
|
||||
sfi0->SetAttribute("MaxSDUSize", UintegerValue(0));
|
||||
n1->AddStreamFilter(sfi0);
|
||||
Ptr<FlowMeterInstance> fm0 = CreateObject<FlowMeterInstance>();
|
||||
fm0->SetAttribute("CIR", DataRateValue(DataRate("40Mb/s")));
|
||||
fm0->SetAttribute("CBS", UintegerValue(1000));
|
||||
fm0->SetAttribute("DropOnYellow", BooleanValue(true));
|
||||
fm0->SetAttribute("MarkAllFramesRedEnable", BooleanValue(false));
|
||||
uint16_t fmid = n1->AddFlowMeter(fm0);
|
||||
sfi0->AddFlowMeterInstanceId(fmid);
|
||||
|
||||
//Application description
|
||||
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
|
||||
app0->Setup(net0);
|
||||
app0->SetAttribute("BurstSize", UintegerValue(4));
|
||||
app0->SetAttribute("PayloadSize", UintegerValue(500));
|
||||
app0->SetAttribute("Period", TimeValue(Seconds(5)));
|
||||
app0->SetAttribute("PCP", UintegerValue(0));
|
||||
app0->SetAttribute("VlanID", UintegerValue(100));
|
||||
|
||||
n0->AddApplication(app0);
|
||||
app0->SetStartTime(Seconds(5));
|
||||
app0->SetStopTime(Seconds(12));
|
||||
|
||||
//Callback to display the packet log
|
||||
std::string context = Names::FindName(n0) + ":" + Names::FindName(net0);
|
||||
net0->TraceConnectWithoutContext("MacTx", MakeBoundCallback(&MacTxCallback, context));
|
||||
context = Names::FindName(n1) + ":" + Names::FindName(net1);
|
||||
net1->TraceConnectWithoutContext("MacRx", MakeBoundCallback(&MacRxCallback, context));
|
||||
net1->TraceConnectWithoutContext("MaxSDUSizeFilterDrop", MakeBoundCallback(&MaxSDUSizeFilterDrop, Names::FindName(net1)));
|
||||
net1->TraceConnectWithoutContext("REDFrameDrop", MakeBoundCallback(&REDFrameDrop, Names::FindName(net1)));
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(Seconds(15));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/applications-module.h"
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/drop-tail-queue.h"
|
||||
|
||||
#include "ns3/tsn-net-device.h"
|
||||
#include "ns3/ethernet-channel.h"
|
||||
#include "ns3/ethernet-generator.h"
|
||||
#include "ns3/ethernet-header2.h"
|
||||
#include "ns3/stream-identification-function-null.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example of the use of tsn-node.cc tsn-net-device.cc ethernet-channel.cc
|
||||
* on a network composed of two end-stations connected by a 100Mb/s
|
||||
* full duplex link
|
||||
* ES1 ====== ES2
|
||||
*/
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("Example");
|
||||
|
||||
//A callback to log the pkt transmission
|
||||
static void
|
||||
MacTxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " entered the transmission FIFO !");
|
||||
}
|
||||
|
||||
//A callback to log the pkt reception
|
||||
static void
|
||||
MacRxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " received !");
|
||||
}
|
||||
|
||||
//Callbacks to log pkt drop
|
||||
static void
|
||||
MaxSDUSizeFilterDrop(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
NS_LOG_INFO(context << " : Packet #"<< p->GetUid() <<" was dropped by MaxSDUSizeFilter ");
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
//Enable logging
|
||||
LogComponentEnable("Example", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("TsnNetDevice", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("StreamFilterInstance", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("EthernetGenerator", LOG_LEVEL_INFO);
|
||||
|
||||
CommandLine cmd(__FILE__);
|
||||
cmd.Parse(argc, argv);
|
||||
|
||||
//Create two nodes
|
||||
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
|
||||
Names::Add("ES1", n0);
|
||||
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
|
||||
Names::Add("ES2", n1);
|
||||
|
||||
//Create and add a netDevice to each node
|
||||
Ptr<TsnNetDevice> net0 = CreateObject<TsnNetDevice>();
|
||||
net0->SetAttribute("DataRate", DataRateValue(DataRate("1Gb/s")));
|
||||
n0->AddDevice(net0);
|
||||
Names::Add("ES1#01", net0);
|
||||
Ptr<TsnNetDevice> net1 = CreateObject<TsnNetDevice>();
|
||||
net1->SetAttribute("DataRate", DataRateValue(DataRate("1Gb/s")));
|
||||
n1->AddDevice(net1);
|
||||
Names::Add("ES2#01", net1);
|
||||
|
||||
//Create a Ethernet Channel and attach it two the two netDevices
|
||||
Ptr<EthernetChannel> channel = CreateObject<EthernetChannel>();
|
||||
net0->Attach(channel);
|
||||
net1->Attach(channel);
|
||||
|
||||
//Allocate a Mac address and create a FIFO (for the output port)
|
||||
//for each netDevice.
|
||||
net0->SetAddress(Mac48Address::Allocate());
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
|
||||
net1->SetAddress(Mac48Address::Allocate());
|
||||
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
|
||||
//Stream identification
|
||||
Ptr<NullStreamIdentificationFunction> sif0 = CreateObject<NullStreamIdentificationFunction>();
|
||||
uint16_t StreamHandle = 10;
|
||||
sif0->SetAttribute("VlanID", UintegerValue(100));
|
||||
sif0->SetAttribute("Address", AddressValue(Mac48Address("ff:ff:ff:ff:ff:ff")));
|
||||
n1->AddStreamIdentificationFunction(StreamHandle, sif0, {net1}, {}, {}, {});
|
||||
//PSFP configuration
|
||||
Ptr<StreamFilterInstance> sfi0 = CreateObject<StreamFilterInstance>();
|
||||
sfi0->SetAttribute("StreamHandle", IntegerValue(StreamHandle));
|
||||
sfi0->SetAttribute("Priority", IntegerValue(-1)); //-1 = wildcard (like in PSFP MIB)
|
||||
sfi0->SetAttribute("MaxSDUSize", UintegerValue(522));
|
||||
sfi0->SetAttribute("StreamBlockedDueToOversizeFrameEnable", BooleanValue(true));
|
||||
n1->AddStreamFilter(sfi0);
|
||||
|
||||
//Application description
|
||||
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
|
||||
app0->Setup(net0);
|
||||
app0->SetAttribute("BurstSize", UintegerValue(2));
|
||||
app0->SetAttribute("PayloadSize", UintegerValue(500));
|
||||
app0->SetAttribute("Period", TimeValue(Seconds(5)));
|
||||
app0->SetAttribute("PCP", UintegerValue(0));
|
||||
app0->SetAttribute("VlanID", UintegerValue(100));
|
||||
|
||||
n0->AddApplication(app0);
|
||||
app0->SetStartTime(Seconds(0));
|
||||
app0->SetStopTime(Seconds(10));
|
||||
|
||||
Ptr<EthernetGenerator> app1 = CreateObject<EthernetGenerator>();
|
||||
app1->Setup(net0);
|
||||
app1->SetAttribute("BurstSize", UintegerValue(1));
|
||||
app1->SetAttribute("PayloadSize", UintegerValue(501));
|
||||
app1->SetAttribute("Period", TimeValue(Seconds(5)));
|
||||
app1->SetAttribute("PCP", UintegerValue(0));
|
||||
app1->SetAttribute("VlanID", UintegerValue(100));
|
||||
|
||||
n0->AddApplication(app1);
|
||||
app1->SetStartTime(Seconds(4));
|
||||
app1->SetStopTime(Seconds(5));
|
||||
|
||||
//Callback to display the packet log
|
||||
std::string context = Names::FindName(n0) + ":" + Names::FindName(net0);
|
||||
net0->TraceConnectWithoutContext("MacTx", MakeBoundCallback(&MacTxCallback, context));
|
||||
context = Names::FindName(n1) + ":" + Names::FindName(net1);
|
||||
net1->TraceConnectWithoutContext("MacRx", MakeBoundCallback(&MacRxCallback, context));
|
||||
net1->TraceConnectWithoutContext("MaxSDUSizeFilterDrop", MakeBoundCallback(&MaxSDUSizeFilterDrop, Names::FindName(net1)));
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(Seconds(10));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
168
contrib/tsn/examples/tsn-point2point-withTAS-CBS.cc
Normal file
168
contrib/tsn/examples/tsn-point2point-withTAS-CBS.cc
Normal file
@@ -0,0 +1,168 @@
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/applications-module.h"
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/drop-tail-queue.h"
|
||||
#include <bitset>
|
||||
|
||||
#include "ns3/tsn-node.h"
|
||||
#include "ns3/tsn-net-device.h"
|
||||
#include "ns3/cbs.h"
|
||||
#include "ns3/ethernet-channel.h"
|
||||
#include "ns3/ethernet-generator.h"
|
||||
#include "ns3/ethernet-header2.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example of the use of tsn-node.cc tsn-net-device.cc ethernet-channel.cc
|
||||
* on a network composed of two end-stations connected by a 100Mb/s
|
||||
* full duplex link with TAS with CBS on ES1 port
|
||||
* ES1 ====== ES2
|
||||
*/
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("Example");
|
||||
|
||||
//A callback to log the pkt reception
|
||||
static void
|
||||
MacRxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " received !");
|
||||
}
|
||||
|
||||
//A callback to log the pkt emission
|
||||
static void
|
||||
PhyTxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " begin transmission !");
|
||||
}
|
||||
|
||||
//A callback to log the gate update
|
||||
static void
|
||||
TasCallback(std::string context, uint8_t states)
|
||||
{
|
||||
Time t = Simulator::Now();
|
||||
std::string str = "";
|
||||
std::string binary = std::bitset<8>(states).to_string();
|
||||
std::reverse(binary.begin(), binary.end());
|
||||
|
||||
for (int i = 0; i < (int)binary.length(); i++) {
|
||||
str += " Fifo " + std::to_string(i);
|
||||
std::string c{binary[i]};
|
||||
int state = std::stoi(c);
|
||||
|
||||
if(state)
|
||||
{
|
||||
str += " Open ;";
|
||||
}
|
||||
else
|
||||
{
|
||||
str += " Close;";
|
||||
}
|
||||
}
|
||||
NS_LOG_INFO(context << " : At "<< t.GetNanoSeconds() <<" Tas gate states update :" << str);
|
||||
}
|
||||
|
||||
//A callback to log the credit value
|
||||
static void
|
||||
CbsCallback(std::string context, double credit)
|
||||
{
|
||||
Time t = Simulator::Now();
|
||||
NS_LOG_INFO("FIFO:" << context << " : At "<< t.GetNanoSeconds() <<" credit=" << credit);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
//Enable logging
|
||||
LogComponentEnable("Example", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("EthernetGenerator", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("Tas", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("Clock", LOG_LEVEL_INFO);
|
||||
|
||||
CommandLine cmd(__FILE__);
|
||||
cmd.Parse(argc, argv);
|
||||
|
||||
//Create two nodes
|
||||
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
|
||||
Names::Add("ES1", n0);
|
||||
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
|
||||
Names::Add("ES2", n1);
|
||||
|
||||
//Add perfect clock on each node
|
||||
n0->AddClock(CreateObject<Clock>());
|
||||
n1->AddClock(CreateObject<Clock>());
|
||||
|
||||
//Create and add a netDevice to each node
|
||||
Ptr<TsnNetDevice> net0 = CreateObject<TsnNetDevice>();
|
||||
net0->SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
|
||||
n0->AddDevice(net0);
|
||||
Names::Add("ES1#01", net0);
|
||||
Ptr<TsnNetDevice> net1 = CreateObject<TsnNetDevice>();
|
||||
net1->SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
|
||||
n1->AddDevice(net1);
|
||||
Names::Add("ES2#01", net1);
|
||||
|
||||
//Create a Ethernet Channel and attach it two the two netDevices
|
||||
Ptr<EthernetChannel> channel = CreateObject<EthernetChannel>();
|
||||
net0->Attach(channel);
|
||||
net1->Attach(channel);
|
||||
|
||||
//Allocate a Mac address
|
||||
net0->SetAddress(Mac48Address::Allocate());
|
||||
net1->SetAddress(Mac48Address::Allocate());
|
||||
|
||||
//Create and add the FIFO 0 on each net device with a cbs on net0's FIFO
|
||||
Ptr<Cbs> cbs = CreateObject<Cbs>();
|
||||
cbs->SetTsnNetDevice(net0);
|
||||
Names::Add(Names::FindName(net0) + "-" + "0", cbs); //NetDeviceName-FifoNumber
|
||||
cbs->SetAttribute("IdleSlope", DataRateValue(DataRate("2Mb/s")));
|
||||
cbs->SetAttribute("portTransmitRate", DataRateValue(DataRate("100Mb/s")));
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>(), cbs);
|
||||
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
|
||||
//Create and add the last seven FIFO on each net device
|
||||
for (int i=0; i<7; i++)
|
||||
{
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
}
|
||||
|
||||
//Callback to display the gate update log (must be before StartTas() to display the initial gate states)
|
||||
net0->GetTas()->TraceConnectWithoutContext("GatesUpdate", MakeBoundCallback(&TasCallback, Names::FindName(net0)));
|
||||
|
||||
//Add two GCL entry on net0 and start TAS
|
||||
net0->AddGclEntry(Time(MilliSeconds(3)), 1);
|
||||
net0->AddGclEntry(Time(MilliSeconds(17)), 0);
|
||||
net0->StartTas();
|
||||
|
||||
//Application description
|
||||
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
|
||||
app0->Setup(net0);
|
||||
app0->SetAttribute("BurstSize", UintegerValue(2));
|
||||
app0->SetAttribute("PayloadSize", UintegerValue(1400));
|
||||
app0->SetAttribute("Period", TimeValue(MilliSeconds(50)));
|
||||
app0->SetAttribute("PCP", UintegerValue(0));
|
||||
app0->SetAttribute("VlanID", UintegerValue(100));
|
||||
n0->AddApplication(app0);
|
||||
app0->SetStartTime(MilliSeconds(0));
|
||||
app0->SetStopTime(MilliSeconds(20));
|
||||
|
||||
//Callback to display the packet transmitted and received log
|
||||
net0->TraceConnectWithoutContext("PhyTxBegin", MakeBoundCallback(&PhyTxCallback, Names::FindName(n0) + ":" + Names::FindName(net0)));
|
||||
net1->TraceConnectWithoutContext("MacRx", MakeBoundCallback(&MacRxCallback, Names::FindName(n1) + ":" + Names::FindName(net1)));
|
||||
|
||||
//Callback to display the credit update log
|
||||
cbs->TraceConnectWithoutContext("Credit", MakeBoundCallback(&CbsCallback, Names::FindName(cbs)));
|
||||
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(MilliSeconds(60));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
199
contrib/tsn/examples/tsn-point2point-withTAS-GuardBand.cc
Normal file
199
contrib/tsn/examples/tsn-point2point-withTAS-GuardBand.cc
Normal file
@@ -0,0 +1,199 @@
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/applications-module.h"
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/drop-tail-queue.h"
|
||||
#include <bitset>
|
||||
|
||||
#include "ns3/tsn-node.h"
|
||||
#include "ns3/tsn-net-device.h"
|
||||
#include "ns3/ethernet-channel.h"
|
||||
#include "ns3/ethernet-generator.h"
|
||||
#include "ns3/ethernet-header2.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example of the use of the use of the different TAS guard band mode on a 100Mb/s
|
||||
* full duplex link with TAS on ES1 port
|
||||
* ES1 ====== ES2
|
||||
*
|
||||
* This example script can be run using one of this two following commands
|
||||
* according to the algorithm needed :
|
||||
* ./ns3 run <path to the script> -- --none
|
||||
* ./ns3 run <path to the script> -- --mtu
|
||||
* ./ns3 run <path to the script> -- --pktsize
|
||||
*
|
||||
*/
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("Example");
|
||||
|
||||
//A callback to log the pkt reception
|
||||
static void
|
||||
MacRxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " received !" << p->ToString());
|
||||
}
|
||||
|
||||
//A callback to log the pkt given to the netDevice by the application
|
||||
static void
|
||||
PktSentCallback(std::string context, Ptr<const Packet> p, uint16_t vid)
|
||||
{
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " given to the netDevice !");
|
||||
}
|
||||
|
||||
//A callback to log the pkt emission
|
||||
static void
|
||||
PhyTxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " begin transmission !");
|
||||
}
|
||||
|
||||
//A callback to log the gate update
|
||||
static void
|
||||
TasCallback(std::string context, uint8_t states)
|
||||
{
|
||||
Time t = Simulator::Now();
|
||||
std::string str = "";
|
||||
std::string binary = std::bitset<8>(states).to_string();
|
||||
std::reverse(binary.begin(), binary.end());
|
||||
|
||||
for (int i = 0; i < (int)binary.length(); i++) {
|
||||
str += " Fifo " + std::to_string(i);
|
||||
std::string c{binary[i]};
|
||||
int state = std::stoi(c);
|
||||
|
||||
if(state)
|
||||
{
|
||||
str += " Open ;";
|
||||
}
|
||||
else
|
||||
{
|
||||
str += " Close;";
|
||||
}
|
||||
}
|
||||
NS_LOG_INFO(context << " : At "<< t.GetNanoSeconds() <<" Tas gate states update :" << str);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
//Enable logging
|
||||
LogComponentEnable("Example", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("EthernetGenerator", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("Tas", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("TsnNetDevice", LOG_LEVEL_INFO);
|
||||
|
||||
//Command line interpretation
|
||||
bool mtu = false;
|
||||
bool pktsize = false;
|
||||
bool none = false;
|
||||
CommandLine cmd(__FILE__);
|
||||
cmd.AddValue("mtu", "Enable mtu guard band mode", mtu);
|
||||
cmd.AddValue("pktsize", "Enable pktsize guard band mode", pktsize);
|
||||
cmd.AddValue("none", "Enable none guard band mode", none);
|
||||
cmd.Parse(argc, argv);
|
||||
if (mtu+pktsize+none > 1)
|
||||
{
|
||||
NS_LOG_INFO("Only one guard band mode can be selected");
|
||||
return 0;
|
||||
}
|
||||
else if (mtu+pktsize+none == 0)
|
||||
{
|
||||
NS_LOG_INFO("A guard band mode must be selected using '--mtu' or '--pktsize' or '--none' ");
|
||||
return 0;
|
||||
}
|
||||
|
||||
//Create two nodes
|
||||
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
|
||||
Names::Add("ES1", n0);
|
||||
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
|
||||
Names::Add("ES2", n1);
|
||||
|
||||
//Add perfect clock on each node
|
||||
n0->AddClock(CreateObject<Clock>());
|
||||
n1->AddClock(CreateObject<Clock>());
|
||||
|
||||
//Create and add a netDevice to each node
|
||||
Ptr<TsnNetDevice> net0 = CreateObject<TsnNetDevice>();
|
||||
net0->SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
|
||||
n0->AddDevice(net0);
|
||||
Names::Add("ES1#01", net0);
|
||||
Ptr<TsnNetDevice> net1 = CreateObject<TsnNetDevice>();
|
||||
net1->SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
|
||||
n1->AddDevice(net1);
|
||||
Names::Add("ES2#01", net1);
|
||||
|
||||
//Create a Ethernet Channel and attach it two the two netDevices
|
||||
Ptr<EthernetChannel> channel = CreateObject<EthernetChannel>();
|
||||
net0->Attach(channel);
|
||||
net1->Attach(channel);
|
||||
|
||||
//Allocate a Mac address
|
||||
net0->SetAddress(Mac48Address::Allocate());
|
||||
net1->SetAddress(Mac48Address::Allocate());
|
||||
|
||||
//Create and add eight FIFO on each net device
|
||||
for (int i=0; i<8; i++)
|
||||
{
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
}
|
||||
|
||||
//Set Tas Guard Band Mode (MTU is the default GuardBandMode)
|
||||
if(mtu)
|
||||
{
|
||||
net0->GetTas()->SetAttribute("GuardBandMode", EnumValue(Tas::MTU));
|
||||
}
|
||||
else if(pktsize)
|
||||
{
|
||||
net0->GetTas()->SetAttribute("GuardBandMode", EnumValue(Tas::PKTSIZE));
|
||||
}
|
||||
else
|
||||
{
|
||||
net0->GetTas()->SetAttribute("GuardBandMode", EnumValue(Tas::NONE));
|
||||
}
|
||||
|
||||
//Callback to display the gate update log (must be before StartTas() to display the initial gate states)
|
||||
net0->GetTas()->TraceConnectWithoutContext("GatesUpdate", MakeBoundCallback(&TasCallback, Names::FindName(net0)));
|
||||
|
||||
//Add two GCL entry on net0 and start TAS
|
||||
net0->AddGclEntry(Time(NanoSeconds(10)), 2);
|
||||
net0->AddGclEntry(Time(NanoSeconds(4990)), 0);
|
||||
net0->AddGclEntry(Time(MicroSeconds(95)), 2);
|
||||
net0->AddGclEntry(Time(MicroSeconds(9900)), 0);
|
||||
net0->AddGclEntry(Time(MilliSeconds(10)), 2);
|
||||
net0->AddGclEntry(Time(MilliSeconds(20)), 0);
|
||||
net0->StartTas();
|
||||
|
||||
//Application description
|
||||
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
|
||||
app0->Setup(net0);
|
||||
app0->SetAttribute("BurstSize", UintegerValue(1));
|
||||
app0->SetAttribute("PayloadSize", UintegerValue(100));
|
||||
app0->SetAttribute("Period", TimeValue(MilliSeconds(40)));
|
||||
app0->SetAttribute("PCP", UintegerValue(1));
|
||||
app0->SetAttribute("VlanID", UintegerValue(100));
|
||||
n0->AddApplication(app0);
|
||||
app0->SetStartTime(Seconds(0));
|
||||
app0->SetStopTime(Seconds(4));
|
||||
|
||||
|
||||
//Callback to display the packet transmitted and received log
|
||||
app0->TraceConnectWithoutContext("PktSent", MakeBoundCallback(&PktSentCallback, Names::FindName(n0) + ":" + Names::FindName(net0)));
|
||||
net0->TraceConnectWithoutContext("PhyTxBegin", MakeBoundCallback(&PhyTxCallback, Names::FindName(n0) + ":" + Names::FindName(net0)));
|
||||
net1->TraceConnectWithoutContext("MacRx", MakeBoundCallback(&MacRxCallback, Names::FindName(n1) + ":" + Names::FindName(net1)));
|
||||
|
||||
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(MilliSeconds(30));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
191
contrib/tsn/examples/tsn-point2point-withTAS-gPTP.cc
Normal file
191
contrib/tsn/examples/tsn-point2point-withTAS-gPTP.cc
Normal file
@@ -0,0 +1,191 @@
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/applications-module.h"
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/drop-tail-queue.h"
|
||||
#include <bitset>
|
||||
|
||||
#include "ns3/tsn-node.h"
|
||||
#include "ns3/tsn-net-device.h"
|
||||
#include "ns3/ethernet-channel.h"
|
||||
#include "ns3/ethernet-generator.h"
|
||||
#include "ns3/ethernet-header2.h"
|
||||
#include "ns3/gPTP.h"
|
||||
#include "ns3/clock.h"
|
||||
#include "ns3/clock-constant-drift.h"
|
||||
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example of the use of tsn-node.cc tsn-net-device.cc ethernet-channel.cc
|
||||
* on a network composed of two end-stations connected by a 100Mb/s
|
||||
* full duplex link with TAS on ES1 port. ES2 is GPTP grandmaster and ES1 is in
|
||||
* slave state.
|
||||
* ES1 ====== ES2
|
||||
*/
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("Example");
|
||||
|
||||
//A callback to log the pkt reception
|
||||
static void
|
||||
MacRxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " received !");
|
||||
}
|
||||
|
||||
//A callback to log the pkt emission
|
||||
static void
|
||||
PhyTxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " begin transmission !");
|
||||
}
|
||||
|
||||
//A callback to log the gate update
|
||||
static void
|
||||
TasCallback(std::string context, uint8_t states)
|
||||
{
|
||||
Time t = Simulator::Now();
|
||||
std::string str = "";
|
||||
std::string binary = std::bitset<8>(states).to_string();
|
||||
std::reverse(binary.begin(), binary.end());
|
||||
|
||||
for (int i = 0; i < (int)binary.length(); i++) {
|
||||
str += " Fifo " + std::to_string(i);
|
||||
std::string c{binary[i]};
|
||||
int state = std::stoi(c);
|
||||
|
||||
if(state)
|
||||
{
|
||||
str += " Open ;";
|
||||
}
|
||||
else
|
||||
{
|
||||
str += " Close;";
|
||||
}
|
||||
}
|
||||
NS_LOG_INFO(context << " : At "<< t.GetNanoSeconds() <<" Tas gate states update :" << str);
|
||||
}
|
||||
|
||||
static void
|
||||
ClockAfterCorrectionCallback(std::string context, Time clockValue)
|
||||
{
|
||||
NS_LOG_INFO("[GPTP] At " << Simulator::Now() << " on "<< context << " clock value after correction = " << clockValue.GetNanoSeconds() << "ns (error = "<< (Simulator::Now()-clockValue).GetNanoSeconds() << "ns)");
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
//Enable logging
|
||||
LogComponentEnable("Example", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("TsnNode", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("TsnNetDevice", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("EthernetGenerator", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("Tas", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("Clock", LOG_LEVEL_INFO);
|
||||
// LogComponentEnable("GPTP", LOG_LEVEL_INFO);
|
||||
|
||||
CommandLine cmd(__FILE__);
|
||||
cmd.Parse(argc, argv);
|
||||
|
||||
//Create two nodes
|
||||
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
|
||||
Names::Add("ES1", n0);
|
||||
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
|
||||
Names::Add("ES2", n1);
|
||||
|
||||
//Create and add clock to TsnNode
|
||||
Ptr<ConstantDriftClock> c0 = CreateObject<ConstantDriftClock>();
|
||||
c0->SetAttribute("InitialOffset", TimeValue(Seconds(5)));
|
||||
c0->SetAttribute("DriftRate", DoubleValue(50));
|
||||
c0->SetAttribute("Granularity", TimeValue(NanoSeconds(1)));
|
||||
n0->SetMainClock(c0);
|
||||
|
||||
Ptr<Clock> c1 = CreateObject<Clock>(); //Perfect clock for the GM
|
||||
n1->SetMainClock(c1);
|
||||
|
||||
//Create and add a netDevice to each node
|
||||
Ptr<TsnNetDevice> net0 = CreateObject<TsnNetDevice>();
|
||||
net0->SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
|
||||
n0->AddDevice(net0);
|
||||
Names::Add("ES1#01", net0);
|
||||
Ptr<TsnNetDevice> net1 = CreateObject<TsnNetDevice>();
|
||||
net1->SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
|
||||
n1->AddDevice(net1);
|
||||
Names::Add("ES2#01", net1);
|
||||
|
||||
//Create a Ethernet Channel and attach it two the two netDevices
|
||||
Ptr<EthernetChannel> channel = CreateObject<EthernetChannel>();
|
||||
channel->SetAttribute("Delay", TimeValue(NanoSeconds(200)));
|
||||
net0->Attach(channel);
|
||||
net1->Attach(channel);
|
||||
|
||||
//Allocate a Mac address
|
||||
net0->SetAddress(Mac48Address::Allocate());
|
||||
net1->SetAddress(Mac48Address::Allocate());
|
||||
|
||||
//Create and add eight FIFO on each net device
|
||||
for (int i=0; i<8; i++)
|
||||
{
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
}
|
||||
|
||||
//Add and configure GPTP
|
||||
Ptr<GPTP> gPTP0 = CreateObject<GPTP>();
|
||||
gPTP0->SetNode(n0);
|
||||
gPTP0->SetMainClock(c0);
|
||||
gPTP0->AddDomain(0);
|
||||
gPTP0->AddPort(net0, GPTP::SLAVE, 0);
|
||||
gPTP0->SetAttribute("Priority", UintegerValue(0));
|
||||
n0->AddApplication(gPTP0);
|
||||
gPTP0->SetStartTime(Seconds(0));
|
||||
|
||||
Ptr<GPTP> gPTP1 = CreateObject<GPTP>();
|
||||
gPTP1->SetNode(n1);
|
||||
gPTP1->SetMainClock(c1);
|
||||
gPTP1->AddDomain(0);
|
||||
gPTP1->AddPort(net1, GPTP::MASTER, 0);
|
||||
gPTP1->SetAttribute("Priority", UintegerValue(0));
|
||||
n1->AddApplication(gPTP1);
|
||||
gPTP1->SetStartTime(Seconds(0));
|
||||
|
||||
//Add two GCL entry on net0 and start TAS
|
||||
//(must be done after GPTP declaration due to clock declaration)
|
||||
net0->AddGclEntry(Time(MilliSeconds(10)), 1);
|
||||
net0->AddGclEntry(Time(MilliSeconds(10)), 2);
|
||||
net0->StartTas();
|
||||
|
||||
//Application description
|
||||
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
|
||||
app0->Setup(net0);
|
||||
app0->SetAttribute("BurstSize", UintegerValue(1));
|
||||
app0->SetAttribute("PayloadSize", UintegerValue(1400));
|
||||
app0->SetAttribute("Period", TimeValue(MilliSeconds(15)));
|
||||
app0->SetAttribute("PCP", UintegerValue(1));
|
||||
app0->SetAttribute("VlanID", UintegerValue(100));
|
||||
n0->AddApplication(app0);
|
||||
app0->SetStartTime(Seconds(0));
|
||||
app0->SetStopTime(Seconds(4));
|
||||
|
||||
//Callback to display the packet transmitted and received log
|
||||
net0->TraceConnectWithoutContext("PhyTxBegin", MakeBoundCallback(&PhyTxCallback, Names::FindName(n0) + ":" + Names::FindName(net0)));
|
||||
net1->TraceConnectWithoutContext("MacRx", MakeBoundCallback(&MacRxCallback, Names::FindName(n1) + ":" + Names::FindName(net1)));
|
||||
|
||||
//Callback to display the gate update log (must be before StartTas() to display the initial gate states)
|
||||
net0->GetTas()->TraceConnectWithoutContext("GatesUpdate", MakeBoundCallback(&TasCallback, Names::FindName(net0)));
|
||||
|
||||
//Callback to monitor synchronization
|
||||
gPTP0->TraceConnectWithoutContext("ClockAfterCorrection", MakeBoundCallback(&ClockAfterCorrectionCallback, Names::FindName(n0)));
|
||||
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(Seconds(1.5));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
148
contrib/tsn/examples/tsn-point2point-withTAS.cc
Normal file
148
contrib/tsn/examples/tsn-point2point-withTAS.cc
Normal file
@@ -0,0 +1,148 @@
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/applications-module.h"
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/drop-tail-queue.h"
|
||||
#include <bitset>
|
||||
|
||||
#include "ns3/tsn-node.h"
|
||||
#include "ns3/tsn-net-device.h"
|
||||
#include "ns3/ethernet-channel.h"
|
||||
#include "ns3/ethernet-generator.h"
|
||||
#include "ns3/ethernet-header2.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example of the use of tsn-node.cc tsn-net-device.cc ethernet-channel.cc
|
||||
* on a network composed of two end-stations connected by a 100Mb/s
|
||||
* full duplex link with TAS on ES1 port
|
||||
* ES1 ====== ES2
|
||||
*/
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("Example");
|
||||
|
||||
//A callback to log the pkt reception
|
||||
static void
|
||||
MacRxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " received !");
|
||||
}
|
||||
|
||||
//A callback to log the pkt emission
|
||||
static void
|
||||
PhyTxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " begin transmission !");
|
||||
}
|
||||
|
||||
//A callback to log the gate update
|
||||
static void
|
||||
TasCallback(std::string context, uint8_t states)
|
||||
{
|
||||
Time t = Simulator::Now();
|
||||
std::string str = "";
|
||||
std::string binary = std::bitset<8>(states).to_string();
|
||||
std::reverse(binary.begin(), binary.end());
|
||||
|
||||
for (int i = 0; i < (int)binary.length(); i++) {
|
||||
str += " Fifo " + std::to_string(i);
|
||||
std::string c{binary[i]};
|
||||
int state = std::stoi(c);
|
||||
|
||||
if(state)
|
||||
{
|
||||
str += " Open ;";
|
||||
}
|
||||
else
|
||||
{
|
||||
str += " Close;";
|
||||
}
|
||||
}
|
||||
NS_LOG_INFO(context << " : At "<< t.GetNanoSeconds() <<" Tas gate states update :" << str);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
//Enable logging
|
||||
LogComponentEnable("Example", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("EthernetGenerator", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("Tas", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("Clock", LOG_LEVEL_INFO);
|
||||
|
||||
CommandLine cmd(__FILE__);
|
||||
cmd.Parse(argc, argv);
|
||||
|
||||
//Create two nodes
|
||||
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
|
||||
Names::Add("ES1", n0);
|
||||
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
|
||||
Names::Add("ES2", n1);
|
||||
|
||||
//Add perfect clock on each node
|
||||
n0->AddClock(CreateObject<Clock>());
|
||||
n1->AddClock(CreateObject<Clock>());
|
||||
|
||||
//Create and add a netDevice to each node
|
||||
Ptr<TsnNetDevice> net0 = CreateObject<TsnNetDevice>();
|
||||
net0->SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
|
||||
n0->AddDevice(net0);
|
||||
Names::Add("ES1#01", net0);
|
||||
Ptr<TsnNetDevice> net1 = CreateObject<TsnNetDevice>();
|
||||
net1->SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
|
||||
n1->AddDevice(net1);
|
||||
Names::Add("ES2#01", net1);
|
||||
|
||||
//Create a Ethernet Channel and attach it two the two netDevices
|
||||
Ptr<EthernetChannel> channel = CreateObject<EthernetChannel>();
|
||||
net0->Attach(channel);
|
||||
net1->Attach(channel);
|
||||
|
||||
//Allocate a Mac address
|
||||
net0->SetAddress(Mac48Address::Allocate());
|
||||
net1->SetAddress(Mac48Address::Allocate());
|
||||
|
||||
//Create and add eight FIFO on each net device
|
||||
for (int i=0; i<8; i++)
|
||||
{
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
}
|
||||
|
||||
//Callback to display the gate update log (must be before StartTas() to display the initial gate states)
|
||||
net0->GetTas()->TraceConnectWithoutContext("GatesUpdate", MakeBoundCallback(&TasCallback, Names::FindName(net0)));
|
||||
|
||||
//Add two GCL entry on net0 and start TAS
|
||||
net0->AddGclEntry(Time(MilliSeconds(10)), 0);
|
||||
net0->AddGclEntry(Time(MilliSeconds(10)), 2);
|
||||
net0->StartTas();
|
||||
|
||||
//Application description
|
||||
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
|
||||
app0->Setup(net0);
|
||||
app0->SetAttribute("BurstSize", UintegerValue(1));
|
||||
app0->SetAttribute("PayloadSize", UintegerValue(1400));
|
||||
app0->SetAttribute("Period", TimeValue(MilliSeconds(15)));
|
||||
app0->SetAttribute("PCP", UintegerValue(1));
|
||||
app0->SetAttribute("VlanID", UintegerValue(100));
|
||||
n0->AddApplication(app0);
|
||||
app0->SetStartTime(Seconds(0));
|
||||
app0->SetStopTime(Seconds(4));
|
||||
|
||||
//Callback to display the packet transmitted and received log
|
||||
net0->TraceConnectWithoutContext("PhyTxBegin", MakeBoundCallback(&PhyTxCallback, Names::FindName(n0) + ":" + Names::FindName(net0)));
|
||||
net1->TraceConnectWithoutContext("MacRx", MakeBoundCallback(&MacRxCallback, Names::FindName(n1) + ":" + Names::FindName(net1)));
|
||||
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(MilliSeconds(80));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
92
contrib/tsn/examples/tsn-point2point.cc
Normal file
92
contrib/tsn/examples/tsn-point2point.cc
Normal file
@@ -0,0 +1,92 @@
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/applications-module.h"
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/drop-tail-queue.h"
|
||||
|
||||
#include "ns3/tsn-net-device.h"
|
||||
#include "ns3/ethernet-channel.h"
|
||||
#include "ns3/ethernet-generator.h"
|
||||
#include "ns3/ethernet-header2.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example of the use of tsn-node.cc tsn-net-device.cc ethernet-channel.cc
|
||||
* on a network composed of two end-stations connected by a 100Mb/s
|
||||
* full duplex link
|
||||
* ES1 ====== ES2
|
||||
*/
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("Example");
|
||||
|
||||
//A callback to log the pkt reception
|
||||
static void
|
||||
MacRxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " received !");
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
//Enable logging
|
||||
LogComponentEnable("Example", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("EthernetGenerator", LOG_LEVEL_INFO);
|
||||
|
||||
CommandLine cmd(__FILE__);
|
||||
cmd.Parse(argc, argv);
|
||||
|
||||
//Create two nodes
|
||||
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
|
||||
Names::Add("ES1", n0);
|
||||
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
|
||||
Names::Add("ES2", n1);
|
||||
|
||||
//Create and add a netDevice to each node
|
||||
Ptr<TsnNetDevice> net0 = CreateObject<TsnNetDevice>();
|
||||
net0->SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
|
||||
n0->AddDevice(net0);
|
||||
Names::Add("ES1#01", net0);
|
||||
Ptr<TsnNetDevice> net1 = CreateObject<TsnNetDevice>();
|
||||
net1->SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
|
||||
n1->AddDevice(net1);
|
||||
Names::Add("ES2#01", net1);
|
||||
|
||||
//Create a Ethernet Channel and attach it two the two netDevices
|
||||
Ptr<EthernetChannel> channel = CreateObject<EthernetChannel>();
|
||||
net0->Attach(channel);
|
||||
net1->Attach(channel);
|
||||
|
||||
//Allocate a Mac address and create a FIFO (for the output port)
|
||||
//for each netDevice.
|
||||
net0->SetAddress(Mac48Address::Allocate());
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
|
||||
net1->SetAddress(Mac48Address::Allocate());
|
||||
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
|
||||
//Application description
|
||||
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
|
||||
app0->Setup(net0);
|
||||
app0->SetAttribute("BurstSize", UintegerValue(2));
|
||||
app0->SetAttribute("PayloadSize", UintegerValue(1400));
|
||||
app0->SetAttribute("Period", TimeValue(Seconds(5)));
|
||||
|
||||
n0->AddApplication(app0);
|
||||
app0->SetStartTime(Seconds(0));
|
||||
app0->SetStopTime(Seconds(10));
|
||||
|
||||
//Callback to display the packet received log
|
||||
std::string context = Names::FindName(n1) + ":" + Names::FindName(net1);
|
||||
net1->TraceConnectWithoutContext("MacRx", MakeBoundCallback(&MacRxCallback, context));
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(Seconds(10));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
301
contrib/tsn/examples/tsn-switched-multidrop.cc
Normal file
301
contrib/tsn/examples/tsn-switched-multidrop.cc
Normal file
@@ -0,0 +1,301 @@
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/applications-module.h"
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/drop-tail-queue.h"
|
||||
#include "ns3/timestamp-tag.h"
|
||||
|
||||
#include "ns3/tsn-multidrop-net-device.h"
|
||||
#include "ns3/tsn-multidrop-channel.h"
|
||||
#include "ns3/tsn-node.h"
|
||||
#include "ns3/tsn-net-device.h"
|
||||
#include "ns3/ethernet-generator.h"
|
||||
#include "ns3/ethernet-header2.h"
|
||||
#include "ns3/ethernet-channel.h"
|
||||
#include "ns3/switch-net-device.h"
|
||||
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example of the use of tsn-net-device.cc tsn-multidrop-channel.cc on a network
|
||||
* switched network with three end-stations connected by a 10Base-T1S
|
||||
* ES1 ==== SW ====== ES2
|
||||
* ||
|
||||
* ||== ES3
|
||||
* ||
|
||||
* ||== ES4
|
||||
*
|
||||
* There is two flows on this network :
|
||||
* - vlanID = 10 from ES1 to ES2
|
||||
* - vlanID = 20 from ES2 to ES1, ES3, ES4
|
||||
*/
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("Example");
|
||||
|
||||
|
||||
//A callback to log pkt fifo entry time
|
||||
static void
|
||||
MacTxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
Ptr<Packet> originalPacket = p->Copy();
|
||||
EthernetHeader2 ethHeader;
|
||||
originalPacket->RemoveHeader(ethHeader);
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << "(VID:" << ethHeader.GetVid() << ") entering the FIFO on the producer");
|
||||
}
|
||||
|
||||
//A callback to log the pkt latency
|
||||
static void
|
||||
LatencyCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
TimestampTag tag;
|
||||
if (!p->FindFirstMatchingByteTag(tag))
|
||||
{
|
||||
return;
|
||||
}
|
||||
Time arrival = Simulator::Now();
|
||||
Time latency = arrival - tag.GetTimestamp();
|
||||
|
||||
Ptr<Packet> originalPacket = p->Copy();
|
||||
EthernetHeader2 ethHeader;
|
||||
originalPacket->RemoveHeader(ethHeader);
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " received from " << ethHeader.GetSrc() << "(VID:" << ethHeader.GetVid() << ") with a latency=" << latency.GetNanoSeconds() <<"ns");
|
||||
}
|
||||
|
||||
//A callback to log the PLCA state
|
||||
static void
|
||||
PLCAStateCallback(std::string context, TsnMultidropNetDevice::PLCAState state)
|
||||
{
|
||||
std::string stateStr = "";
|
||||
if ( state == TsnMultidropNetDevice::PLCAState::DISABLE)
|
||||
{
|
||||
stateStr = "DISABLE";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::RECOVER)
|
||||
{
|
||||
stateStr = "RECOVER";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::RESYNC)
|
||||
{
|
||||
stateStr = "RESYNC";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::SEND_BEACON)
|
||||
{
|
||||
stateStr = "SEND_BEACON";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::SYNCING)
|
||||
{
|
||||
stateStr = "SYNCING";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::WAIT_TO)
|
||||
{
|
||||
stateStr = "WAIT_TO";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::COMMIT)
|
||||
{
|
||||
stateStr = "COMMIT";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::TRANSMIT)
|
||||
{
|
||||
stateStr = "TRANSMIT";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::BURST)
|
||||
{
|
||||
stateStr = "BURST";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::RECEIVE)
|
||||
{
|
||||
stateStr = "RECEIVE";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::YIELD)
|
||||
{
|
||||
stateStr = "YIELD";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::ABORT)
|
||||
{
|
||||
stateStr = "ABORT";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::NEXT_TX_OPPORTUNITY)
|
||||
{
|
||||
stateStr = "NEXT_TX_OPPORTUNITY";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::EARLY_RECEIVE)
|
||||
{
|
||||
stateStr = "EARLY_RECEIVE";
|
||||
}
|
||||
else
|
||||
{
|
||||
stateStr = "UNKNOWN_STATE";
|
||||
}
|
||||
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : PLCAState => " << stateStr);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
//Enable logging
|
||||
LogComponentEnable("Example", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("EthernetGenerator", LOG_LEVEL_INFO);
|
||||
// LogComponentEnable("TsnMultidropNetDevice", LOG_LEVEL_INFO);
|
||||
// LogComponentEnable("TsnMultidropNetChannel", LOG_LEVEL_INFO);
|
||||
|
||||
CommandLine cmd(__FILE__);
|
||||
cmd.Parse(argc, argv);
|
||||
|
||||
//Create four nodes
|
||||
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
|
||||
Names::Add("ES1", n0);
|
||||
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
|
||||
Names::Add("ES2", n1);
|
||||
Ptr<TsnNode> n2 = CreateObject<TsnNode>();
|
||||
Names::Add("ES3", n2);
|
||||
Ptr<TsnNode> n3 = CreateObject<TsnNode>();
|
||||
Names::Add("ES4", n3);
|
||||
Ptr<TsnNode> n4 = CreateObject<TsnNode>();
|
||||
Names::Add("SW", n4);
|
||||
|
||||
|
||||
//Create and add a netDevice to each node
|
||||
Ptr<TsnNetDevice> net0 = CreateObject<TsnNetDevice>();
|
||||
n0->AddDevice(net0);
|
||||
Names::Add("ES1#01", net0);
|
||||
Ptr<TsnNetDevice> swnet0 = CreateObject<TsnNetDevice>();
|
||||
n4->AddDevice(swnet0);
|
||||
Names::Add("SW#01", swnet0);
|
||||
|
||||
Ptr<TsnMultidropNetDevice> swnet1 = CreateObject<TsnMultidropNetDevice>();
|
||||
swnet1->SetAttribute("PLCALocalNodeId", UintegerValue(0));
|
||||
swnet1->SetAttribute("PLCANodeCount", UintegerValue(4));
|
||||
n4->AddDevice(swnet1);
|
||||
Names::Add("SW#02", swnet1);
|
||||
Ptr<TsnMultidropNetDevice> net1 = CreateObject<TsnMultidropNetDevice>();
|
||||
net1->SetAttribute("PLCALocalNodeId", UintegerValue(1));
|
||||
net1->SetAttribute("PLCANodeCount", UintegerValue(4));
|
||||
n1->AddDevice(net1);
|
||||
Names::Add("ES2#01", net1);
|
||||
Ptr<TsnMultidropNetDevice> net2 = CreateObject<TsnMultidropNetDevice>();
|
||||
net2->SetAttribute("PLCALocalNodeId", UintegerValue(2));
|
||||
net2->SetAttribute("PLCANodeCount", UintegerValue(4));
|
||||
n2->AddDevice(net2);
|
||||
Names::Add("ES3#01", net2);
|
||||
Ptr<TsnMultidropNetDevice> net3 = CreateObject<TsnMultidropNetDevice>();
|
||||
net3->SetAttribute("PLCALocalNodeId", UintegerValue(3));
|
||||
net3->SetAttribute("PLCANodeCount", UintegerValue(4));
|
||||
n3->AddDevice(net3);
|
||||
Names::Add("ES4#01", net3);
|
||||
|
||||
|
||||
//Create a full-duplex channel
|
||||
Ptr<EthernetChannel> channel0 = CreateObject<EthernetChannel>();
|
||||
net0->Attach(channel0);
|
||||
swnet0->Attach(channel0);
|
||||
|
||||
//Create a 10Base-T1S Channel and attach it two the netDevices
|
||||
Ptr<TsnMultidropChannel> channel1 = CreateObject<TsnMultidropChannel>();
|
||||
swnet1->Attach(channel1);
|
||||
net1->Attach(channel1);
|
||||
net2->Attach(channel1);
|
||||
net3->Attach(channel1);
|
||||
|
||||
//Create and add a switch net device to the switch node
|
||||
Ptr<SwitchNetDevice> sw = CreateObject<SwitchNetDevice>();
|
||||
sw->SetAttribute("MinForwardingLatency", TimeValue(MicroSeconds(10)));
|
||||
sw->SetAttribute("MaxForwardingLatency", TimeValue(MicroSeconds(10)));
|
||||
n4->AddDevice(sw);
|
||||
sw->AddSwitchPort(swnet0);
|
||||
sw->AddSwitchPort(swnet1);
|
||||
|
||||
|
||||
//Allocate a Mac address and create a FIFO (for the output port)
|
||||
//for each netDevice.
|
||||
net0->SetAddress(Mac48Address::Allocate());
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
|
||||
net1->SetAddress(Mac48Address::Allocate());
|
||||
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
|
||||
net2->SetAddress(Mac48Address::Allocate());
|
||||
net2->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net2->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
|
||||
net3->SetAddress(Mac48Address::Allocate());
|
||||
net3->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net3->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
|
||||
swnet0->SetAddress(Mac48Address::Allocate());
|
||||
swnet0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
swnet0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
|
||||
swnet1->SetAddress(Mac48Address::Allocate());
|
||||
swnet1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
swnet1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
|
||||
//Add forwarding table
|
||||
sw->AddForwardingTableEntry(Mac48Address::ConvertFrom(net2->GetAddress()), 10, {swnet1});
|
||||
sw->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 20, {swnet0});
|
||||
|
||||
//Application description
|
||||
//From switched network to 10Base-T1S
|
||||
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
|
||||
app0->Setup(net0);
|
||||
app0->SetAttribute("Address", AddressValue(net2->GetAddress()));
|
||||
app0->SetAttribute("BurstSize", UintegerValue(2));
|
||||
app0->SetAttribute("PayloadSize", UintegerValue(1400));
|
||||
app0->SetAttribute("Period", TimeValue(Seconds(5)));
|
||||
app0->SetAttribute("VlanID", UintegerValue(10));
|
||||
app0->SetAttribute("PCP", UintegerValue(0));
|
||||
|
||||
n0->AddApplication(app0);
|
||||
app0->SetStartTime(Seconds(0));
|
||||
app0->SetStopTime(Seconds(10));
|
||||
|
||||
//From 10Base-T1S to switched network
|
||||
Ptr<EthernetGenerator> app1 = CreateObject<EthernetGenerator>();
|
||||
app1->Setup(net1);
|
||||
app1->SetAttribute("BurstSize", UintegerValue(1));
|
||||
app1->SetAttribute("PayloadSize", UintegerValue(100));
|
||||
app1->SetAttribute("Period", TimeValue(Seconds(5)));
|
||||
app1->SetAttribute("VlanID", UintegerValue(20));
|
||||
app1->SetAttribute("PCP", UintegerValue(1));
|
||||
|
||||
n1->AddApplication(app1);
|
||||
app1->SetStartTime(Seconds(0));
|
||||
app1->SetStopTime(Seconds(10));
|
||||
|
||||
|
||||
//Callback to log pkt fifo entry time
|
||||
std::string context = Names::FindName(n0) + ":" + Names::FindName(net0);
|
||||
net0->TraceConnectWithoutContext("MacTx", MakeBoundCallback(&MacTxCallback, context));
|
||||
context = Names::FindName(n1) + ":" + Names::FindName(net1);
|
||||
net1->TraceConnectWithoutContext("MacTx", MakeBoundCallback(&MacTxCallback, context));
|
||||
|
||||
//Callback to display the packet latency
|
||||
context = Names::FindName(n0) + ":" + Names::FindName(net0);
|
||||
net0->TraceConnectWithoutContext("Latency", MakeBoundCallback(&LatencyCallback, context));
|
||||
context = Names::FindName(n1) + ":" + Names::FindName(net1);
|
||||
net1->TraceConnectWithoutContext("Latency", MakeBoundCallback(&LatencyCallback, context));
|
||||
context = Names::FindName(n2) + ":" + Names::FindName(net2);
|
||||
net2->TraceConnectWithoutContext("Latency", MakeBoundCallback(&LatencyCallback, context));
|
||||
context = Names::FindName(n3) + ":" + Names::FindName(net3);
|
||||
net3->TraceConnectWithoutContext("Latency", MakeBoundCallback(&LatencyCallback, context));
|
||||
|
||||
//Callback to display PLCA state evolution
|
||||
swnet1->TraceConnectWithoutContext("PLCAState", MakeBoundCallback(&PLCAStateCallback, Names::FindName(swnet1)));
|
||||
// net1->TraceConnectWithoutContext("PLCAState", MakeBoundCallback(&PLCAStateCallback, Names::FindName(net1)));
|
||||
// net2->TraceConnectWithoutContext("PLCAState", MakeBoundCallback(&PLCAStateCallback, Names::FindName(net2)));
|
||||
// net3->TraceConnectWithoutContext("PLCAState", MakeBoundCallback(&PLCAStateCallback, Names::FindName(net3)));
|
||||
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(MilliSeconds(3));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
358
contrib/tsn/examples/tsn-switched-withFRER-activeSid.cc
Normal file
358
contrib/tsn/examples/tsn-switched-withFRER-activeSid.cc
Normal file
@@ -0,0 +1,358 @@
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/applications-module.h"
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/drop-tail-queue.h"
|
||||
#include "ns3/trace-helper.h"
|
||||
#include <fstream>
|
||||
|
||||
#include "ns3/tsn-node.h"
|
||||
#include "ns3/tsn-net-device.h"
|
||||
#include "ns3/switch-net-device.h"
|
||||
#include "ns3/ethernet-channel.h"
|
||||
#include "ns3/ethernet-generator.h"
|
||||
#include "ns3/ethernet-header2.h"
|
||||
#include "ns3/stream-identification-function.h"
|
||||
#include "ns3/stream-identification-function-null.h"
|
||||
#include "ns3/stream-identification-function-active-dest-mac-vlan.h"
|
||||
#include "ns3/frer-sequence-generation-function.h"
|
||||
#include "ns3/frer-sequence-recovery-function.h"
|
||||
#include "ns3/frer-latent-error-detection-function.h"
|
||||
#include "ns3/frer-match-recovery-function.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example with 2ES connected 4SW in a 1Gb/s full duplex link to demonstrate
|
||||
* FRER usage. To be more specific this example use the SW1 to do the replication
|
||||
* using mulitcast and SW4 to do the elimination. The stream identification is
|
||||
* done by the active mac dest and vlan stream identification function. The match recovery function,
|
||||
* latent error detection function are also used in this example.
|
||||
* Two flows go from ESsource to ESdest. Only the VLAN 100 and 101 flow use FRER mechanisms.
|
||||
* To be more specific ESsource send a VLAN 100 packet that is replicated toward
|
||||
* SW 2 with VLAN 100 and toward SW 3 with VLAN 101. A non replicated packet
|
||||
* using VLAN 102 cross the network.
|
||||
*
|
||||
* / ==== SW2 ==== \
|
||||
* ESsource ==== SW1 SW4 ==== ESdest
|
||||
* \ ==== SW3 ==== /
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("Example");
|
||||
|
||||
//A callback to log the pkt reception
|
||||
static void
|
||||
MacRxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
Ptr<Packet> originalPacket = p->Copy();
|
||||
EthernetHeader2 ethHeader;
|
||||
originalPacket->RemoveHeader(ethHeader);
|
||||
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " (VID:" << ethHeader.GetVid() << ") received !");
|
||||
}
|
||||
|
||||
//A callback to log the pkt emission
|
||||
static void
|
||||
PhyTxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
Ptr<Packet> originalPacket = p->Copy();
|
||||
EthernetHeader2 ethHeader;
|
||||
originalPacket->RemoveHeader(ethHeader);
|
||||
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " (VID:" << ethHeader.GetVid() << ") begin transmission !");
|
||||
}
|
||||
|
||||
//A callback to log pkt elimination
|
||||
static void
|
||||
FrerDrop(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
NS_LOG_INFO(context << " : An instance of Packet #"<< p->GetUid() <<" was dropped by FRER recovery function");
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
//Enable logging
|
||||
LogComponentEnable("Example", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("EthernetGenerator", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("ActiveDestMacVlanStreamIdentificationFunction", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("TsnNetDevice", LOG_LEVEL_INFO);
|
||||
|
||||
CommandLine cmd(__FILE__);
|
||||
cmd.Parse(argc, argv);
|
||||
|
||||
//Create six nodes
|
||||
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
|
||||
Names::Add("ESsource", n0);
|
||||
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
|
||||
Names::Add("ESdest", n1);
|
||||
Ptr<TsnNode> n2 = CreateObject<TsnNode>();
|
||||
Names::Add("SW1", n2);
|
||||
Ptr<TsnNode> n3 = CreateObject<TsnNode>();
|
||||
Names::Add("SW2", n3);
|
||||
Ptr<TsnNode> n4 = CreateObject<TsnNode>();
|
||||
Names::Add("SW3", n4);
|
||||
Ptr<TsnNode> n5 = CreateObject<TsnNode>();
|
||||
Names::Add("SW4", n5);
|
||||
|
||||
//Create and add a netDevices to each node
|
||||
Ptr<TsnNetDevice> net0 = CreateObject<TsnNetDevice>();
|
||||
n0->AddDevice(net0);
|
||||
Names::Add("ESsource#01", net0);
|
||||
Ptr<TsnNetDevice> net1 = CreateObject<TsnNetDevice>();
|
||||
n1->AddDevice(net1);
|
||||
Names::Add("ESdest#01", net1);
|
||||
|
||||
Ptr<TsnNetDevice> net2_1 = CreateObject<TsnNetDevice>();
|
||||
n2->AddDevice(net2_1);
|
||||
Ptr<TsnNetDevice> net2_2 = CreateObject<TsnNetDevice>();
|
||||
n2->AddDevice(net2_2);
|
||||
Ptr<TsnNetDevice> net2_3 = CreateObject<TsnNetDevice>();
|
||||
n2->AddDevice(net2_3);
|
||||
|
||||
Ptr<TsnNetDevice> net3_1 = CreateObject<TsnNetDevice>();
|
||||
n3->AddDevice(net3_1);
|
||||
Ptr<TsnNetDevice> net3_2 = CreateObject<TsnNetDevice>();
|
||||
n3->AddDevice(net3_2);
|
||||
|
||||
Ptr<TsnNetDevice> net4_1 = CreateObject<TsnNetDevice>();
|
||||
n4->AddDevice(net4_1);
|
||||
Ptr<TsnNetDevice> net4_2 = CreateObject<TsnNetDevice>();
|
||||
n4->AddDevice(net4_2);
|
||||
|
||||
Ptr<TsnNetDevice> net5_1 = CreateObject<TsnNetDevice>();
|
||||
n5->AddDevice(net5_1);
|
||||
Ptr<TsnNetDevice> net5_2 = CreateObject<TsnNetDevice>();
|
||||
n5->AddDevice(net5_2);
|
||||
Ptr<TsnNetDevice> net5_3 = CreateObject<TsnNetDevice>();
|
||||
n5->AddDevice(net5_3);
|
||||
|
||||
//Create Ethernet Channels and attach it to the netDevices
|
||||
Ptr<EthernetChannel> l0 = CreateObject<EthernetChannel>();
|
||||
l0->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
net0->Attach(l0);
|
||||
net2_1->Attach(l0);
|
||||
Ptr<EthernetChannel> l1 = CreateObject<EthernetChannel>();
|
||||
l1->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
net2_2->Attach(l1);
|
||||
net3_1->Attach(l1);
|
||||
Ptr<EthernetChannel> l2 = CreateObject<EthernetChannel>();
|
||||
l2->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
net2_3->Attach(l2);
|
||||
net4_1->Attach(l2);
|
||||
Ptr<EthernetChannel> l3 = CreateObject<EthernetChannel>();
|
||||
l3->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
net3_2->Attach(l3);
|
||||
net5_1->Attach(l3);
|
||||
Ptr<EthernetChannel> l4 = CreateObject<EthernetChannel>();
|
||||
l4->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
net4_2->Attach(l4);
|
||||
net5_2->Attach(l4);
|
||||
Ptr<EthernetChannel> l5 = CreateObject<EthernetChannel>();
|
||||
l5->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
net5_3->Attach(l5);
|
||||
net1->Attach(l5);
|
||||
|
||||
//Create and add switche net devices to the switch nodes
|
||||
Ptr<SwitchNetDevice> sw1 = CreateObject<SwitchNetDevice>();
|
||||
sw1->SetAttribute("MinForwardingLatency", TimeValue(MicroSeconds(10)));
|
||||
sw1->SetAttribute("MaxForwardingLatency", TimeValue(MicroSeconds(10)));
|
||||
n2->AddDevice(sw1);
|
||||
sw1->AddSwitchPort(net2_1);
|
||||
sw1->AddSwitchPort(net2_2);
|
||||
sw1->AddSwitchPort(net2_3);
|
||||
Ptr<SwitchNetDevice> sw2 = CreateObject<SwitchNetDevice>();
|
||||
sw2->SetAttribute("MinForwardingLatency", TimeValue(MicroSeconds(10)));
|
||||
sw2->SetAttribute("MaxForwardingLatency", TimeValue(MicroSeconds(10)));
|
||||
n3->AddDevice(sw2);
|
||||
sw2->AddSwitchPort(net3_1);
|
||||
sw2->AddSwitchPort(net3_2);
|
||||
Ptr<SwitchNetDevice> sw3 = CreateObject<SwitchNetDevice>();
|
||||
sw3->SetAttribute("MinForwardingLatency", TimeValue(MicroSeconds(10)));
|
||||
sw3->SetAttribute("MaxForwardingLatency", TimeValue(MicroSeconds(10)));
|
||||
n4->AddDevice(sw3);
|
||||
sw3->AddSwitchPort(net4_1);
|
||||
sw3->AddSwitchPort(net4_2);
|
||||
Ptr<SwitchNetDevice> sw4 = CreateObject<SwitchNetDevice>();
|
||||
sw4->SetAttribute("MinForwardingLatency", TimeValue(MicroSeconds(10)));
|
||||
sw4->SetAttribute("MaxForwardingLatency", TimeValue(MicroSeconds(10)));
|
||||
n5->AddDevice(sw4);
|
||||
sw4->AddSwitchPort(net5_1);
|
||||
sw4->AddSwitchPort(net5_2);
|
||||
sw4->AddSwitchPort(net5_3);
|
||||
|
||||
//Allocate a Mac address
|
||||
net0->SetAddress(Mac48Address::Allocate());
|
||||
net1->SetAddress(Mac48Address::Allocate());
|
||||
sw1->SetAddress(Mac48Address::Allocate());
|
||||
sw2->SetAddress(Mac48Address::Allocate());
|
||||
sw3->SetAddress(Mac48Address::Allocate());
|
||||
sw4->SetAddress(Mac48Address::Allocate());
|
||||
|
||||
//Create and add eight FIFO on each net device
|
||||
for (int i=0; i<8; i++)
|
||||
{
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net2_1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net2_2->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net2_3->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net3_1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net3_2->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net4_1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net4_2->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net5_1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net5_2->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net5_3->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
}
|
||||
|
||||
//Add forwarding table
|
||||
sw1->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 100, {net2_2, net2_3});
|
||||
sw2->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 100, {net3_2});
|
||||
sw3->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 101, {net4_2});
|
||||
sw4->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 100, {net5_3});
|
||||
sw4->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 101, {net5_3});
|
||||
|
||||
sw1->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 102, {net2_2});
|
||||
sw2->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 102, {net3_2});
|
||||
sw4->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 102, {net5_3});
|
||||
|
||||
//Stream Indentification + FRER
|
||||
//First switch
|
||||
//Stream identification
|
||||
Ptr<NullStreamIdentificationFunction> sif0 = CreateObject<NullStreamIdentificationFunction>();
|
||||
uint16_t StreamHandle = 1;
|
||||
sif0->SetAttribute("VlanID", UintegerValue(100));
|
||||
sif0->SetAttribute("Address", AddressValue(Mac48Address("ff:ff:ff:ff:ff:ff")));
|
||||
n2->AddStreamIdentificationFunction(StreamHandle, sif0, {net2_1}, {}, {}, {});
|
||||
//Sequencing : Sequence generation
|
||||
Ptr<SequenceGenerationFunction> seqf0 = CreateObject<SequenceGenerationFunction>();
|
||||
seqf0->SetAttribute("Direction", BooleanValue(false)); //in-facing
|
||||
seqf0->SetStreamHandle({StreamHandle});
|
||||
n2->AddSequenceGenerationFunction(seqf0);
|
||||
//Sequence encode
|
||||
Ptr<SequenceEncodeDecodeFunction> seqEnc0 = CreateObject<SequenceEncodeDecodeFunction>();
|
||||
seqEnc0->SetAttribute("Direction", BooleanValue(false)); //in-facing
|
||||
seqEnc0->SetAttribute("Active", BooleanValue(true));
|
||||
seqEnc0->SetStreamHandle({StreamHandle});
|
||||
seqEnc0->SetPort(net2_1);
|
||||
n2->AddSequenceEncodeDecodeFunction(seqEnc0);
|
||||
//Active Stream identification to change the vlan on net2_3
|
||||
Ptr<ActiveDestMacVlanStreamIdentificationFunction> sif1 = CreateObject<ActiveDestMacVlanStreamIdentificationFunction>();
|
||||
sif1->SetAttribute("VlanID", UintegerValue(100));
|
||||
sif1->SetAttribute("UpdateVlanID", UintegerValue(101));
|
||||
sif1->SetAttribute("Address", AddressValue(Mac48Address("ff:ff:ff:ff:ff:ff")));
|
||||
sif1->SetAttribute("UpdateAddress", AddressValue(Mac48Address("ff:ff:ff:ff:ff:ff")));
|
||||
sif1->SetAttribute("UpdatePCP", UintegerValue(1));
|
||||
n2->AddStreamIdentificationFunction(StreamHandle, sif1, {}, {}, {}, {net2_3});
|
||||
|
||||
//Last switch
|
||||
//Stream identification
|
||||
Ptr<NullStreamIdentificationFunction> sif2 = CreateObject<NullStreamIdentificationFunction>();
|
||||
StreamHandle = 1;
|
||||
sif2->SetAttribute("VlanID", UintegerValue(100));
|
||||
sif2->SetAttribute("Address", AddressValue(Mac48Address("ff:ff:ff:ff:ff:ff")));
|
||||
n5->AddStreamIdentificationFunction(StreamHandle, sif2, {}, {}, {net5_3}, {});
|
||||
|
||||
Ptr<NullStreamIdentificationFunction> sif3 = CreateObject<NullStreamIdentificationFunction>();
|
||||
sif3->SetAttribute("VlanID", UintegerValue(101));
|
||||
sif3->SetAttribute("Address", AddressValue(Mac48Address("ff:ff:ff:ff:ff:ff")));
|
||||
n5->AddStreamIdentificationFunction(StreamHandle, sif3, {}, {}, {net5_3}, {});
|
||||
|
||||
//Sequence Decode
|
||||
Ptr<SequenceEncodeDecodeFunction> seqEnc1 = CreateObject<SequenceEncodeDecodeFunction>();
|
||||
seqEnc1->SetAttribute("Direction", BooleanValue(false)); //in-facing
|
||||
seqEnc1->SetAttribute("Active", BooleanValue(false));
|
||||
seqEnc1->SetStreamHandle({StreamHandle});
|
||||
seqEnc1->SetPort(net5_3);
|
||||
n5->AddSequenceEncodeDecodeFunction(seqEnc1);
|
||||
//Sequencing : Sequence recovery
|
||||
Ptr<SequenceRecoveryFunction> seqfreco0 = CreateObject<SequenceRecoveryFunction>();
|
||||
seqfreco0->SetAttribute("Direction", BooleanValue(false)); //in-facing
|
||||
seqfreco0->SetAttribute("TakeNoSequence", BooleanValue(false));
|
||||
seqfreco0->SetAttribute("IndividualRecovery", BooleanValue(false));
|
||||
seqfreco0->SetStreamHandle({StreamHandle});
|
||||
seqfreco0->SetPorts({net5_3});
|
||||
n5->AddSequenceRecoveryFunction(seqfreco0);
|
||||
//Sequencing : Sequence recovery : recovery function
|
||||
Ptr<MatchRecoveryFunction> recf0 = CreateObject<MatchRecoveryFunction>();
|
||||
seqfreco0->SetRecoveryFunction(recf0);
|
||||
//Sequencing : Sequence recovery : latent error detection function
|
||||
Ptr<LatentErrorDetectionFunction> latf0 = CreateObject<LatentErrorDetectionFunction>();
|
||||
latf0->SetAttribute("LatentErrorPaths", UintegerValue(2));
|
||||
latf0->SetRecoveryFunction(recf0);
|
||||
seqfreco0->SetLatentErrorDetectionFunction(latf0);
|
||||
//Active stream identification to change back vlanId (optional)
|
||||
Ptr<ActiveDestMacVlanStreamIdentificationFunction> sif4 = CreateObject<ActiveDestMacVlanStreamIdentificationFunction>();
|
||||
sif4->SetAttribute("VlanID", UintegerValue(101));
|
||||
sif4->SetAttribute("UpdateVlanID", UintegerValue(100));
|
||||
sif4->SetAttribute("Address", AddressValue(Mac48Address("ff:ff:ff:ff:ff:ff")));
|
||||
sif4->SetAttribute("UpdateAddress", AddressValue(Mac48Address("ff:ff:ff:ff:ff:ff")));
|
||||
sif4->SetAttribute("UpdatePCP", UintegerValue(1));
|
||||
n5->AddStreamIdentificationFunction(StreamHandle, sif4, {}, {}, {}, {net5_3});
|
||||
|
||||
//Application description
|
||||
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
|
||||
app0->Setup(net0);
|
||||
app0->SetAttribute("BurstSize", UintegerValue(1));
|
||||
app0->SetAttribute("PayloadSize", UintegerValue(1400));
|
||||
app0->SetAttribute("Period", TimeValue(MilliSeconds(10)));
|
||||
app0->SetAttribute("PCP", UintegerValue(1));
|
||||
app0->SetAttribute("VlanID", UintegerValue(100));
|
||||
n0->AddApplication(app0);
|
||||
app0->SetStartTime(MilliSeconds(0));
|
||||
app0->SetStopTime(MilliSeconds(20));
|
||||
|
||||
Ptr<EthernetGenerator> app1 = CreateObject<EthernetGenerator>();
|
||||
app1->Setup(net0);
|
||||
app1->SetAttribute("BurstSize", UintegerValue(1));
|
||||
app1->SetAttribute("PayloadSize", UintegerValue(1400));
|
||||
app1->SetAttribute("Period", TimeValue(MilliSeconds(20)));
|
||||
app1->SetAttribute("PCP", UintegerValue(0));
|
||||
app1->SetAttribute("VlanID", UintegerValue(102));
|
||||
n0->AddApplication(app1);
|
||||
app1->SetStartTime(Seconds(0));
|
||||
app1->SetStopTime(MilliSeconds(41));
|
||||
|
||||
//Callback to display the packet transmitted and received log
|
||||
//Packet::EnablePrinting();
|
||||
net0->TraceConnectWithoutContext("PhyTxBegin", MakeBoundCallback(&PhyTxCallback, Names::FindName(n0) + ":" + Names::FindName(net0)));
|
||||
net1->TraceConnectWithoutContext("MacRx", MakeBoundCallback(&MacRxCallback, Names::FindName(n1) + ":" + Names::FindName(net1)));
|
||||
|
||||
//Callback to display the packet elimination on last output port
|
||||
net5_3->TraceConnectWithoutContext("FrerDrop", MakeBoundCallback(&FrerDrop, Names::FindName(net5_3)));
|
||||
|
||||
//Enable pcap generation
|
||||
PcapHelper pcapHelper;
|
||||
std::string pcapFilename;
|
||||
std::string prefix = "Active-stream-identification";
|
||||
Ptr<PcapFileWrapper> file;
|
||||
pcapFilename = pcapHelper.GetFilenameFromDevice(prefix, net0);
|
||||
file = pcapHelper.CreateFile(pcapFilename, std::ios::out, PcapHelper::DLT_EN10MB);
|
||||
pcapHelper.HookDefaultSink<EthernetNetDevice>(net0, "Sniffer", file);
|
||||
|
||||
pcapFilename = pcapHelper.GetFilenameFromDevice(prefix, net2_2);
|
||||
file = pcapHelper.CreateFile(pcapFilename, std::ios::out, PcapHelper::DLT_EN10MB);
|
||||
pcapHelper.HookDefaultSink<EthernetNetDevice>(net2_2, "Sniffer", file);
|
||||
|
||||
pcapFilename = pcapHelper.GetFilenameFromDevice(prefix, net2_3);
|
||||
file = pcapHelper.CreateFile(pcapFilename, std::ios::out, PcapHelper::DLT_EN10MB);
|
||||
pcapHelper.HookDefaultSink<EthernetNetDevice>(net2_3, "Sniffer", file);
|
||||
|
||||
pcapFilename = pcapHelper.GetFilenameFromDevice(prefix, net1);
|
||||
file = pcapHelper.CreateFile(pcapFilename, std::ios::out, PcapHelper::DLT_EN10MB);
|
||||
pcapHelper.HookDefaultSink<EthernetNetDevice>(net1, "Sniffer", file);
|
||||
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(MilliSeconds(50));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
362
contrib/tsn/examples/tsn-switched-withFRER-recoveryAlgo.cc
Normal file
362
contrib/tsn/examples/tsn-switched-withFRER-recoveryAlgo.cc
Normal file
@@ -0,0 +1,362 @@
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/applications-module.h"
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/drop-tail-queue.h"
|
||||
|
||||
#include "ns3/tsn-node.h"
|
||||
#include "ns3/tsn-net-device.h"
|
||||
#include "ns3/switch-net-device.h"
|
||||
#include "ns3/ethernet-channel.h"
|
||||
#include "ns3/ethernet-generator.h"
|
||||
#include "ns3/ethernet-header2.h"
|
||||
#include "ns3/stream-identification-function.h"
|
||||
#include "ns3/stream-identification-function-null.h"
|
||||
#include "ns3/frer-sequence-generation-function.h"
|
||||
#include "ns3/frer-sequence-recovery-function.h"
|
||||
#include "ns3/frer-latent-error-detection-function.h"
|
||||
#include "ns3/frer-match-recovery-function.h"
|
||||
#include "ns3/frer-vector-recovery-function.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example with 3ES connected 4SW in a 1Gb/s full duplex link to demonstrate
|
||||
* the difference between two FRER sub-mechanisms : the match recovery algorithm
|
||||
* and the vector recovery algorithm. To be more specific this example use the
|
||||
* SW1 to do the replication using mulitcast and SW4 to do the elimination for
|
||||
* the flow with VlanId = 100. The stream identification is done by the null
|
||||
* stream identification function. The match recovery function, latent error
|
||||
* detection function are also used in this example. The Vlan 100 flow go from
|
||||
* ESsource to ESdest and Vlan 101 flow go from ESPerturbation1 to ESdest.
|
||||
*
|
||||
* ESPerturbation1
|
||||
* ||
|
||||
* / ==== SW2 ==== \
|
||||
* ESsource ==== SW1 SW4 ==== ESdest
|
||||
* \ ==== SW3 ==== /
|
||||
*
|
||||
* When using match recovery algorithm, we can note that some packet are received
|
||||
* multiple times (pkt #2, #3, #4, #5, ..., #9) because Vlan 100 flow is bursty
|
||||
* and disrupt by the Vlan 101 flow. This behavior is not observed with vector
|
||||
* recovery algorithm because it store multiple FRER sequence number to do
|
||||
* the elimination.
|
||||
*
|
||||
*
|
||||
* This example script can be run using one of this two following commands
|
||||
* according to the algorithm needed :
|
||||
* ./ns3 run <path to the script> -- --match
|
||||
* ./ns3 run <path to the script> -- --vector
|
||||
*/
|
||||
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("Example");
|
||||
|
||||
//A callback to log the pkt reception
|
||||
static void
|
||||
MacRxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
Ptr<Packet> originalPacket = p->Copy();
|
||||
EthernetHeader2 ethHeader;
|
||||
originalPacket->RemoveHeader(ethHeader);
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " (VID:" << ethHeader.GetVid() << ") received !");
|
||||
}
|
||||
|
||||
//A callback to log the pkt emission
|
||||
static void
|
||||
PhyTxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
Ptr<Packet> originalPacket = p->Copy();
|
||||
EthernetHeader2 ethHeader;
|
||||
originalPacket->RemoveHeader(ethHeader);
|
||||
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " (VID:" << ethHeader.GetVid() << ") begin transmission !");
|
||||
}
|
||||
|
||||
//A callback to log pkt elimination
|
||||
static void
|
||||
FrerDrop(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
NS_LOG_INFO(context << " : An instance of Packet #"<< p->GetUid() <<" was dropped by FRER recovery function");
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
//Enable logging
|
||||
LogComponentEnable("Example", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("EthernetGenerator", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("TsnNetDevice", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("VectorRecoveryFunction", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("MatchRecoveryFunction", LOG_LEVEL_INFO);
|
||||
|
||||
//Command line interpretation
|
||||
bool enableMatch = false;
|
||||
bool enableVector = false;
|
||||
CommandLine cmd(__FILE__);
|
||||
cmd.AddValue("match", "Enable match recovery algorithm", enableMatch);
|
||||
cmd.AddValue("vector", "Enable vector recovery algorithm", enableVector);
|
||||
cmd.Parse(argc, argv);
|
||||
if (enableMatch && enableVector)
|
||||
{
|
||||
NS_LOG_INFO("Only one recovery algorithm can be selected");
|
||||
return 0;
|
||||
}
|
||||
else if (!enableMatch && !enableVector)
|
||||
{
|
||||
NS_LOG_INFO("A recovery algorithm must be selected using '--match' or '--vector' ");
|
||||
return 0;
|
||||
}
|
||||
|
||||
//Create seven nodes
|
||||
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
|
||||
Names::Add("ESsource", n0);
|
||||
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
|
||||
Names::Add("ESdest", n1);
|
||||
Ptr<TsnNode> n2 = CreateObject<TsnNode>();
|
||||
Names::Add("SW1", n2);
|
||||
Ptr<TsnNode> n3 = CreateObject<TsnNode>();
|
||||
Names::Add("SW2", n3);
|
||||
Ptr<TsnNode> n4 = CreateObject<TsnNode>();
|
||||
Names::Add("SW3", n4);
|
||||
Ptr<TsnNode> n5 = CreateObject<TsnNode>();
|
||||
Names::Add("SW4", n5);
|
||||
Ptr<TsnNode> n6 = CreateObject<TsnNode>();
|
||||
Names::Add("ESPerturbation1", n6);
|
||||
|
||||
//Create and add a netDevices to each node
|
||||
Ptr<TsnNetDevice> net0 = CreateObject<TsnNetDevice>();
|
||||
n0->AddDevice(net0);
|
||||
Names::Add("ESsource#01", net0);
|
||||
Ptr<TsnNetDevice> net1 = CreateObject<TsnNetDevice>();
|
||||
n1->AddDevice(net1);
|
||||
Names::Add("ESdest#01", net1);
|
||||
Ptr<TsnNetDevice> net6 = CreateObject<TsnNetDevice>();
|
||||
n6->AddDevice(net6);
|
||||
Names::Add("ESPerturbation1#01", net6);
|
||||
|
||||
Ptr<TsnNetDevice> net2_1 = CreateObject<TsnNetDevice>();
|
||||
n2->AddDevice(net2_1);
|
||||
Ptr<TsnNetDevice> net2_2 = CreateObject<TsnNetDevice>();
|
||||
n2->AddDevice(net2_2);
|
||||
Ptr<TsnNetDevice> net2_3 = CreateObject<TsnNetDevice>();
|
||||
n2->AddDevice(net2_3);
|
||||
|
||||
Ptr<TsnNetDevice> net3_1 = CreateObject<TsnNetDevice>();
|
||||
n3->AddDevice(net3_1);
|
||||
Ptr<TsnNetDevice> net3_2 = CreateObject<TsnNetDevice>();
|
||||
n3->AddDevice(net3_2);
|
||||
Ptr<TsnNetDevice> net3_3 = CreateObject<TsnNetDevice>();
|
||||
n3->AddDevice(net3_3);
|
||||
|
||||
Ptr<TsnNetDevice> net4_1 = CreateObject<TsnNetDevice>();
|
||||
n4->AddDevice(net4_1);
|
||||
Ptr<TsnNetDevice> net4_2 = CreateObject<TsnNetDevice>();
|
||||
n4->AddDevice(net4_2);
|
||||
|
||||
Ptr<TsnNetDevice> net5_1 = CreateObject<TsnNetDevice>();
|
||||
n5->AddDevice(net5_1);
|
||||
Ptr<TsnNetDevice> net5_2 = CreateObject<TsnNetDevice>();
|
||||
n5->AddDevice(net5_2);
|
||||
Ptr<TsnNetDevice> net5_3 = CreateObject<TsnNetDevice>();
|
||||
n5->AddDevice(net5_3);
|
||||
|
||||
//Create Ethernet Channels and attach it to the netDevices
|
||||
Ptr<EthernetChannel> l0 = CreateObject<EthernetChannel>();
|
||||
l0->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
net0->Attach(l0);
|
||||
net2_1->Attach(l0);
|
||||
Ptr<EthernetChannel> l1 = CreateObject<EthernetChannel>();
|
||||
l1->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
net2_2->Attach(l1);
|
||||
net3_1->Attach(l1);
|
||||
Ptr<EthernetChannel> l2 = CreateObject<EthernetChannel>();
|
||||
l2->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
net2_3->Attach(l2);
|
||||
net4_1->Attach(l2);
|
||||
Ptr<EthernetChannel> l3 = CreateObject<EthernetChannel>();
|
||||
l3->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
net3_2->Attach(l3);
|
||||
net5_1->Attach(l3);
|
||||
Ptr<EthernetChannel> l4 = CreateObject<EthernetChannel>();
|
||||
l4->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
net4_2->Attach(l4);
|
||||
net5_2->Attach(l4);
|
||||
Ptr<EthernetChannel> l5 = CreateObject<EthernetChannel>();
|
||||
l5->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
net5_3->Attach(l5);
|
||||
net1->Attach(l5);
|
||||
Ptr<EthernetChannel> l6 = CreateObject<EthernetChannel>();
|
||||
l6->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
net3_3->Attach(l6);
|
||||
net6->Attach(l6);
|
||||
|
||||
//Create and add switche net devices to the switch nodes
|
||||
Ptr<SwitchNetDevice> sw1 = CreateObject<SwitchNetDevice>();
|
||||
sw1->SetAttribute("MinForwardingLatency", TimeValue(MicroSeconds(10)));
|
||||
sw1->SetAttribute("MaxForwardingLatency", TimeValue(MicroSeconds(10)));
|
||||
n2->AddDevice(sw1);
|
||||
sw1->AddSwitchPort(net2_1);
|
||||
sw1->AddSwitchPort(net2_2);
|
||||
sw1->AddSwitchPort(net2_3);
|
||||
Ptr<SwitchNetDevice> sw2 = CreateObject<SwitchNetDevice>();
|
||||
sw2->SetAttribute("MinForwardingLatency", TimeValue(MicroSeconds(10)));
|
||||
sw2->SetAttribute("MaxForwardingLatency", TimeValue(MicroSeconds(10)));
|
||||
n3->AddDevice(sw2);
|
||||
sw2->AddSwitchPort(net3_1);
|
||||
sw2->AddSwitchPort(net3_2);
|
||||
sw2->AddSwitchPort(net3_3);
|
||||
Ptr<SwitchNetDevice> sw3 = CreateObject<SwitchNetDevice>();
|
||||
sw3->SetAttribute("MinForwardingLatency", TimeValue(MicroSeconds(10)));
|
||||
sw3->SetAttribute("MaxForwardingLatency", TimeValue(MicroSeconds(10)));
|
||||
n4->AddDevice(sw3);
|
||||
sw3->AddSwitchPort(net4_1);
|
||||
sw3->AddSwitchPort(net4_2);
|
||||
Ptr<SwitchNetDevice> sw4 = CreateObject<SwitchNetDevice>();
|
||||
sw4->SetAttribute("MinForwardingLatency", TimeValue(MicroSeconds(10)));
|
||||
sw4->SetAttribute("MaxForwardingLatency", TimeValue(MicroSeconds(10)));
|
||||
n5->AddDevice(sw4);
|
||||
sw4->AddSwitchPort(net5_1);
|
||||
sw4->AddSwitchPort(net5_2);
|
||||
sw4->AddSwitchPort(net5_3);
|
||||
|
||||
//Allocate a Mac address
|
||||
net0->SetAddress(Mac48Address::Allocate());
|
||||
net1->SetAddress(Mac48Address::Allocate());
|
||||
sw1->SetAddress(Mac48Address::Allocate());
|
||||
sw2->SetAddress(Mac48Address::Allocate());
|
||||
sw3->SetAddress(Mac48Address::Allocate());
|
||||
sw4->SetAddress(Mac48Address::Allocate());
|
||||
|
||||
//Create and add eight FIFO on each net device
|
||||
for (int i=0; i<8; i++)
|
||||
{
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net2_1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net2_2->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net2_3->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net3_1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net3_2->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net3_3->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net4_1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net4_2->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net5_1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net5_2->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net5_3->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net6->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
}
|
||||
|
||||
//Add forwarding table
|
||||
sw1->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 100, {net2_2, net2_3});
|
||||
sw2->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 100, {net3_2});
|
||||
sw3->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 100, {net4_2});
|
||||
sw4->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 100, {net5_3});
|
||||
|
||||
sw2->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 101, {net3_2});
|
||||
sw4->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 101, {net5_3});
|
||||
|
||||
//Stream Indentification + FRER
|
||||
//First switch
|
||||
//Stream identification
|
||||
Ptr<NullStreamIdentificationFunction> sif0 = CreateObject<NullStreamIdentificationFunction>();
|
||||
uint16_t StreamHandle = 1;
|
||||
sif0->SetAttribute("VlanID", UintegerValue(100));
|
||||
sif0->SetAttribute("Address", AddressValue(Mac48Address("ff:ff:ff:ff:ff:ff")));
|
||||
n2->AddStreamIdentificationFunction(StreamHandle, sif0, {net2_1}, {}, {}, {});
|
||||
//Sequencing : Sequence generation
|
||||
Ptr<SequenceGenerationFunction> seqf0 = CreateObject<SequenceGenerationFunction>();
|
||||
seqf0->SetAttribute("Direction", BooleanValue(false)); //in-facing
|
||||
seqf0->SetStreamHandle({StreamHandle});
|
||||
n2->AddSequenceGenerationFunction(seqf0);
|
||||
//Sequence encode
|
||||
Ptr<SequenceEncodeDecodeFunction> seqEnc0 = CreateObject<SequenceEncodeDecodeFunction>();
|
||||
seqEnc0->SetAttribute("Direction", BooleanValue(false)); //in-facing
|
||||
seqEnc0->SetAttribute("Active", BooleanValue(true));
|
||||
seqEnc0->SetStreamHandle({StreamHandle});
|
||||
seqEnc0->SetPort(net2_1);
|
||||
n2->AddSequenceEncodeDecodeFunction(seqEnc0);
|
||||
|
||||
//Last switch
|
||||
//Stream identification
|
||||
Ptr<NullStreamIdentificationFunction> sif1 = CreateObject<NullStreamIdentificationFunction>();
|
||||
StreamHandle = 1;
|
||||
sif1->SetAttribute("VlanID", UintegerValue(100));
|
||||
sif1->SetAttribute("Address", AddressValue(Mac48Address("ff:ff:ff:ff:ff:ff")));
|
||||
n5->AddStreamIdentificationFunction(StreamHandle, sif1, {}, {}, {net5_3}, {});
|
||||
//Sequence Decode
|
||||
Ptr<SequenceEncodeDecodeFunction> seqEnc1 = CreateObject<SequenceEncodeDecodeFunction>();
|
||||
seqEnc1->SetAttribute("Direction", BooleanValue(false)); //in-facing
|
||||
seqEnc1->SetAttribute("Active", BooleanValue(false));
|
||||
seqEnc1->SetStreamHandle({StreamHandle});
|
||||
seqEnc1->SetPort(net5_3);
|
||||
n5->AddSequenceEncodeDecodeFunction(seqEnc1);
|
||||
//Sequencing : Sequence recovery
|
||||
Ptr<SequenceRecoveryFunction> seqfreco0 = CreateObject<SequenceRecoveryFunction>();
|
||||
seqfreco0->SetAttribute("Direction", BooleanValue(false)); //in-facing
|
||||
seqfreco0->SetAttribute("TakeNoSequence", BooleanValue(false));
|
||||
seqfreco0->SetAttribute("IndividualRecovery", BooleanValue(false));
|
||||
seqfreco0->SetStreamHandle({StreamHandle});
|
||||
seqfreco0->SetPorts({net5_3});
|
||||
n5->AddSequenceRecoveryFunction(seqfreco0);
|
||||
//Sequencing : Sequence recovery : recovery function
|
||||
Ptr<BaseRecoveryFunction> recf0 = nullptr;
|
||||
if (enableVector){
|
||||
recf0 = CreateObject<VectorRecoveryFunction>();
|
||||
recf0->SetAttribute("HistoryLenght", UintegerValue(10));
|
||||
}
|
||||
else if(enableMatch)
|
||||
{
|
||||
recf0 = CreateObject<MatchRecoveryFunction>();
|
||||
}
|
||||
seqfreco0->SetRecoveryFunction(recf0);
|
||||
//Sequencing : Sequence recovery : latent error detection function
|
||||
Ptr<LatentErrorDetectionFunction> latf0 = CreateObject<LatentErrorDetectionFunction>();
|
||||
latf0->SetAttribute("LatentErrorPaths", UintegerValue(2));
|
||||
latf0->SetRecoveryFunction(recf0);
|
||||
seqfreco0->SetLatentErrorDetectionFunction(latf0);
|
||||
|
||||
//Application description
|
||||
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
|
||||
app0->Setup(net0);
|
||||
app0->SetAttribute("BurstSize", UintegerValue(10));
|
||||
app0->SetAttribute("PayloadSize", UintegerValue(1400));
|
||||
app0->SetAttribute("Period", TimeValue(MilliSeconds(20)));
|
||||
app0->SetAttribute("PCP", UintegerValue(1));
|
||||
app0->SetAttribute("VlanID", UintegerValue(100));
|
||||
n0->AddApplication(app0);
|
||||
app0->SetStartTime(MilliSeconds(0));
|
||||
app0->SetStopTime(MilliSeconds(20));
|
||||
|
||||
Ptr<EthernetGenerator> app1 = CreateObject<EthernetGenerator>();
|
||||
app1->Setup(net6);
|
||||
app1->SetAttribute("BurstSize", UintegerValue(3));
|
||||
app1->SetAttribute("PayloadSize", UintegerValue(1400));
|
||||
app1->SetAttribute("Period", TimeValue(MilliSeconds(20)));
|
||||
app1->SetAttribute("PCP", UintegerValue(2));
|
||||
app1->SetAttribute("VlanID", UintegerValue(101));
|
||||
app1->SetAttribute("Offset", TimeValue(MicroSeconds(40)));
|
||||
n6->AddApplication(app1);
|
||||
app1->SetStartTime(MicroSeconds(0));
|
||||
app1->SetStopTime(MilliSeconds(20));
|
||||
|
||||
|
||||
//Callback to display the packet transmitted and received log
|
||||
//Packet::EnablePrinting();
|
||||
net0->TraceConnectWithoutContext("PhyTxBegin", MakeBoundCallback(&PhyTxCallback, Names::FindName(n0) + ":" + Names::FindName(net0)));
|
||||
net6->TraceConnectWithoutContext("PhyTxBegin", MakeBoundCallback(&PhyTxCallback, Names::FindName(n6) + ":" + Names::FindName(net6)));
|
||||
net1->TraceConnectWithoutContext("MacRx", MakeBoundCallback(&MacRxCallback, Names::FindName(n1) + ":" + Names::FindName(net1)));
|
||||
|
||||
//Callback to display the packet elimination on last output port
|
||||
net5_3->TraceConnectWithoutContext("FrerDrop", MakeBoundCallback(&FrerDrop, Names::FindName(net5_3)));
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(MilliSeconds(40));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
320
contrib/tsn/examples/tsn-switched-withFRER.cc
Normal file
320
contrib/tsn/examples/tsn-switched-withFRER.cc
Normal file
@@ -0,0 +1,320 @@
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/applications-module.h"
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/drop-tail-queue.h"
|
||||
#include "ns3/trace-helper.h"
|
||||
|
||||
#include "ns3/tsn-node.h"
|
||||
#include "ns3/tsn-net-device.h"
|
||||
#include "ns3/switch-net-device.h"
|
||||
#include "ns3/ethernet-channel.h"
|
||||
#include "ns3/ethernet-generator.h"
|
||||
#include "ns3/ethernet-header2.h"
|
||||
#include "ns3/stream-identification-function.h"
|
||||
#include "ns3/stream-identification-function-null.h"
|
||||
#include "ns3/frer-sequence-generation-function.h"
|
||||
#include "ns3/frer-sequence-recovery-function.h"
|
||||
#include "ns3/frer-latent-error-detection-function.h"
|
||||
#include "ns3/frer-match-recovery-function.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example with 2ES connected 4SW in a 1Gb/s full duplex link to demonstrate
|
||||
* FRER usage. To be more specific this example use the SW1 to do the replication
|
||||
* using mulitcast and SW4 to do the elimination. The stream identification is
|
||||
* done by the null stream identification function. The match recovery function,
|
||||
* latent error detection function are also used in this example.
|
||||
* Two flows go from ESsource to ESdest. Only the VLAN 100 flow use FRER mechanisms.
|
||||
*
|
||||
* / ==== SW2 ==== \
|
||||
* ESsource ==== SW1 SW4 ==== ESdest
|
||||
* \ ==== SW3 ==== /
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("Example");
|
||||
|
||||
//A callback to log the pkt reception
|
||||
static void
|
||||
MacRxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
Ptr<Packet> originalPacket = p->Copy();
|
||||
EthernetHeader2 ethHeader;
|
||||
originalPacket->RemoveHeader(ethHeader);
|
||||
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " (VID:" << ethHeader.GetVid() << ") received !");
|
||||
}
|
||||
|
||||
//A callback to log the pkt emission
|
||||
static void
|
||||
PhyTxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
Ptr<Packet> originalPacket = p->Copy();
|
||||
EthernetHeader2 ethHeader;
|
||||
originalPacket->RemoveHeader(ethHeader);
|
||||
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " (VID:" << ethHeader.GetVid() << ") begin transmission !");
|
||||
}
|
||||
|
||||
//A callback to log pkt elimination
|
||||
static void
|
||||
FrerDrop(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
NS_LOG_INFO(context << " : An instance of Packet #"<< p->GetUid() <<" was dropped by FRER recovery function");
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
//Enable logging
|
||||
LogComponentEnable("Example", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("EthernetGenerator", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("TsnNetDevice", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("StreamIdEntry", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("NullStreamIdentificationFunction", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("SequenceGenerationFunction", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("SequenceEncodeDecodeFunction", LOG_LEVEL_INFO);
|
||||
|
||||
CommandLine cmd(__FILE__);
|
||||
cmd.Parse(argc, argv);
|
||||
|
||||
//Create six nodes
|
||||
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
|
||||
Names::Add("ESsource", n0);
|
||||
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
|
||||
Names::Add("ESdest", n1);
|
||||
Ptr<TsnNode> n2 = CreateObject<TsnNode>();
|
||||
Names::Add("SW1", n2);
|
||||
Ptr<TsnNode> n3 = CreateObject<TsnNode>();
|
||||
Names::Add("SW2", n3);
|
||||
Ptr<TsnNode> n4 = CreateObject<TsnNode>();
|
||||
Names::Add("SW3", n4);
|
||||
Ptr<TsnNode> n5 = CreateObject<TsnNode>();
|
||||
Names::Add("SW4", n5);
|
||||
|
||||
//Create and add a netDevices to each node
|
||||
Ptr<TsnNetDevice> net0 = CreateObject<TsnNetDevice>();
|
||||
n0->AddDevice(net0);
|
||||
Names::Add("ESsource#01", net0);
|
||||
Ptr<TsnNetDevice> net1 = CreateObject<TsnNetDevice>();
|
||||
n1->AddDevice(net1);
|
||||
Names::Add("ESdest#01", net1);
|
||||
|
||||
Ptr<TsnNetDevice> net2_1 = CreateObject<TsnNetDevice>();
|
||||
n2->AddDevice(net2_1);
|
||||
Names::Add("SW1#01", net2_1);
|
||||
Ptr<TsnNetDevice> net2_2 = CreateObject<TsnNetDevice>();
|
||||
n2->AddDevice(net2_2);
|
||||
Ptr<TsnNetDevice> net2_3 = CreateObject<TsnNetDevice>();
|
||||
n2->AddDevice(net2_3);
|
||||
|
||||
Ptr<TsnNetDevice> net3_1 = CreateObject<TsnNetDevice>();
|
||||
n3->AddDevice(net3_1);
|
||||
Ptr<TsnNetDevice> net3_2 = CreateObject<TsnNetDevice>();
|
||||
n3->AddDevice(net3_2);
|
||||
|
||||
Ptr<TsnNetDevice> net4_1 = CreateObject<TsnNetDevice>();
|
||||
n4->AddDevice(net4_1);
|
||||
Ptr<TsnNetDevice> net4_2 = CreateObject<TsnNetDevice>();
|
||||
n4->AddDevice(net4_2);
|
||||
|
||||
Ptr<TsnNetDevice> net5_1 = CreateObject<TsnNetDevice>();
|
||||
n5->AddDevice(net5_1);
|
||||
Ptr<TsnNetDevice> net5_2 = CreateObject<TsnNetDevice>();
|
||||
n5->AddDevice(net5_2);
|
||||
Ptr<TsnNetDevice> net5_3 = CreateObject<TsnNetDevice>();
|
||||
n5->AddDevice(net5_3);
|
||||
|
||||
//Create Ethernet Channels and attach it to the netDevices
|
||||
Ptr<EthernetChannel> l0 = CreateObject<EthernetChannel>();
|
||||
l0->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
net0->Attach(l0);
|
||||
net2_1->Attach(l0);
|
||||
Ptr<EthernetChannel> l1 = CreateObject<EthernetChannel>();
|
||||
l1->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
net2_2->Attach(l1);
|
||||
net3_1->Attach(l1);
|
||||
Ptr<EthernetChannel> l2 = CreateObject<EthernetChannel>();
|
||||
l2->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
net2_3->Attach(l2);
|
||||
net4_1->Attach(l2);
|
||||
Ptr<EthernetChannel> l3 = CreateObject<EthernetChannel>();
|
||||
l3->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
net3_2->Attach(l3);
|
||||
net5_1->Attach(l3);
|
||||
Ptr<EthernetChannel> l4 = CreateObject<EthernetChannel>();
|
||||
l4->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
net4_2->Attach(l4);
|
||||
net5_2->Attach(l4);
|
||||
Ptr<EthernetChannel> l5 = CreateObject<EthernetChannel>();
|
||||
l5->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
net5_3->Attach(l5);
|
||||
net1->Attach(l5);
|
||||
|
||||
//Create and add switche net devices to the switch nodes
|
||||
Ptr<SwitchNetDevice> sw1 = CreateObject<SwitchNetDevice>();
|
||||
sw1->SetAttribute("MinForwardingLatency", TimeValue(MicroSeconds(10)));
|
||||
sw1->SetAttribute("MaxForwardingLatency", TimeValue(MicroSeconds(10)));
|
||||
n2->AddDevice(sw1);
|
||||
sw1->AddSwitchPort(net2_1);
|
||||
sw1->AddSwitchPort(net2_2);
|
||||
sw1->AddSwitchPort(net2_3);
|
||||
Ptr<SwitchNetDevice> sw2 = CreateObject<SwitchNetDevice>();
|
||||
sw2->SetAttribute("MinForwardingLatency", TimeValue(MicroSeconds(10)));
|
||||
sw2->SetAttribute("MaxForwardingLatency", TimeValue(MicroSeconds(10)));
|
||||
n3->AddDevice(sw2);
|
||||
sw2->AddSwitchPort(net3_1);
|
||||
sw2->AddSwitchPort(net3_2);
|
||||
Ptr<SwitchNetDevice> sw3 = CreateObject<SwitchNetDevice>();
|
||||
sw3->SetAttribute("MinForwardingLatency", TimeValue(MicroSeconds(10)));
|
||||
sw3->SetAttribute("MaxForwardingLatency", TimeValue(MicroSeconds(10)));
|
||||
n4->AddDevice(sw3);
|
||||
sw3->AddSwitchPort(net4_1);
|
||||
sw3->AddSwitchPort(net4_2);
|
||||
Ptr<SwitchNetDevice> sw4 = CreateObject<SwitchNetDevice>();
|
||||
sw4->SetAttribute("MinForwardingLatency", TimeValue(MicroSeconds(10)));
|
||||
sw4->SetAttribute("MaxForwardingLatency", TimeValue(MicroSeconds(10)));
|
||||
n5->AddDevice(sw4);
|
||||
sw4->AddSwitchPort(net5_1);
|
||||
sw4->AddSwitchPort(net5_2);
|
||||
sw4->AddSwitchPort(net5_3);
|
||||
|
||||
//Allocate a Mac address
|
||||
net0->SetAddress(Mac48Address::Allocate());
|
||||
net1->SetAddress(Mac48Address::Allocate());
|
||||
sw1->SetAddress(Mac48Address::Allocate());
|
||||
sw2->SetAddress(Mac48Address::Allocate());
|
||||
sw3->SetAddress(Mac48Address::Allocate());
|
||||
sw4->SetAddress(Mac48Address::Allocate());
|
||||
|
||||
//Create and add eight FIFO on each net device
|
||||
for (int i=0; i<8; i++)
|
||||
{
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net2_1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net2_2->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net2_3->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net3_1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net3_2->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net4_1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net4_2->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net5_1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net5_2->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net5_3->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
}
|
||||
|
||||
//Add forwarding table
|
||||
sw1->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 100, {net2_2, net2_3});
|
||||
sw2->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 100, {net3_2});
|
||||
sw3->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 100, {net4_2});
|
||||
sw4->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 100, {net5_3});
|
||||
|
||||
sw1->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 101, {net2_2});
|
||||
sw2->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 101, {net3_2});
|
||||
sw4->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 101, {net5_3});
|
||||
|
||||
//Stream Indentification + FRER
|
||||
//First switch
|
||||
//Stream identification
|
||||
Ptr<NullStreamIdentificationFunction> sif0 = CreateObject<NullStreamIdentificationFunction>();
|
||||
uint16_t StreamHandle = 1;
|
||||
sif0->SetAttribute("VlanID", UintegerValue(100));
|
||||
sif0->SetAttribute("Address", AddressValue(Mac48Address("ff:ff:ff:ff:ff:ff")));
|
||||
n2->AddStreamIdentificationFunction(StreamHandle, sif0, {net2_1}, {}, {}, {});
|
||||
//Sequencing : Sequence generation
|
||||
Ptr<SequenceGenerationFunction> seqf0 = CreateObject<SequenceGenerationFunction>();
|
||||
seqf0->SetAttribute("Direction", BooleanValue(false)); //in-facing
|
||||
seqf0->SetStreamHandle({StreamHandle});
|
||||
n2->AddSequenceGenerationFunction(seqf0);
|
||||
//Sequence encode
|
||||
Ptr<SequenceEncodeDecodeFunction> seqEnc0 = CreateObject<SequenceEncodeDecodeFunction>();
|
||||
seqEnc0->SetAttribute("Direction", BooleanValue(false)); //in-facing
|
||||
seqEnc0->SetAttribute("Active", BooleanValue(true));
|
||||
seqEnc0->SetStreamHandle({StreamHandle});
|
||||
seqEnc0->SetPort(net2_1);
|
||||
n2->AddSequenceEncodeDecodeFunction(seqEnc0);
|
||||
|
||||
//Last switch
|
||||
//Stream identification
|
||||
Ptr<NullStreamIdentificationFunction> sif1 = CreateObject<NullStreamIdentificationFunction>();
|
||||
StreamHandle = 1;
|
||||
sif1->SetAttribute("VlanID", UintegerValue(100));
|
||||
sif1->SetAttribute("Address", AddressValue(Mac48Address("ff:ff:ff:ff:ff:ff")));
|
||||
n5->AddStreamIdentificationFunction(StreamHandle, sif1, {}, {}, {net5_3}, {});
|
||||
//Sequence Decode
|
||||
Ptr<SequenceEncodeDecodeFunction> seqEnc1 = CreateObject<SequenceEncodeDecodeFunction>();
|
||||
seqEnc1->SetAttribute("Direction", BooleanValue(false)); //in-facing
|
||||
seqEnc1->SetAttribute("Active", BooleanValue(false));
|
||||
seqEnc1->SetStreamHandle({StreamHandle});
|
||||
seqEnc1->SetPort(net5_3);
|
||||
n5->AddSequenceEncodeDecodeFunction(seqEnc1);
|
||||
//Sequencing : Sequence recovery
|
||||
Ptr<SequenceRecoveryFunction> seqfreco0 = CreateObject<SequenceRecoveryFunction>();
|
||||
seqfreco0->SetAttribute("Direction", BooleanValue(false)); //in-facing
|
||||
seqfreco0->SetAttribute("TakeNoSequence", BooleanValue(false));
|
||||
seqfreco0->SetAttribute("IndividualRecovery", BooleanValue(false));
|
||||
seqfreco0->SetStreamHandle({StreamHandle});
|
||||
seqfreco0->SetPorts({net5_3});
|
||||
n5->AddSequenceRecoveryFunction(seqfreco0);
|
||||
//Sequencing : Sequence recovery : recovery function
|
||||
Ptr<MatchRecoveryFunction> recf0 = CreateObject<MatchRecoveryFunction>();
|
||||
seqfreco0->SetRecoveryFunction(recf0);
|
||||
//Sequencing : Sequence recovery : latent error detection function
|
||||
Ptr<LatentErrorDetectionFunction> latf0 = CreateObject<LatentErrorDetectionFunction>();
|
||||
latf0->SetAttribute("LatentErrorPaths", UintegerValue(2));
|
||||
latf0->SetRecoveryFunction(recf0);
|
||||
seqfreco0->SetLatentErrorDetectionFunction(latf0);
|
||||
|
||||
//Application description
|
||||
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
|
||||
app0->Setup(net0);
|
||||
app0->SetAttribute("BurstSize", UintegerValue(1));
|
||||
app0->SetAttribute("PayloadSize", UintegerValue(1400));
|
||||
app0->SetAttribute("Period", TimeValue(MilliSeconds(10)));
|
||||
app0->SetAttribute("PCP", UintegerValue(1));
|
||||
app0->SetAttribute("VlanID", UintegerValue(100));
|
||||
n0->AddApplication(app0);
|
||||
app0->SetStartTime(MilliSeconds(0));
|
||||
app0->SetStopTime(MilliSeconds(20));
|
||||
|
||||
Ptr<EthernetGenerator> app1 = CreateObject<EthernetGenerator>();
|
||||
app1->Setup(net0);
|
||||
app1->SetAttribute("BurstSize", UintegerValue(1));
|
||||
app1->SetAttribute("PayloadSize", UintegerValue(1400));
|
||||
app1->SetAttribute("Period", TimeValue(MilliSeconds(20)));
|
||||
app1->SetAttribute("PCP", UintegerValue(0));
|
||||
app1->SetAttribute("VlanID", UintegerValue(101));
|
||||
n0->AddApplication(app1);
|
||||
app1->SetStartTime(Seconds(0));
|
||||
app1->SetStopTime(MilliSeconds(41));
|
||||
|
||||
//Callback to display the packet transmitted and received log
|
||||
//Packet::EnablePrinting();
|
||||
net0->TraceConnectWithoutContext("PhyTxBegin", MakeBoundCallback(&PhyTxCallback, Names::FindName(n0) + ":" + Names::FindName(net0)));
|
||||
net1->TraceConnectWithoutContext("MacRx", MakeBoundCallback(&MacRxCallback, Names::FindName(n1) + ":" + Names::FindName(net1)));
|
||||
|
||||
//Callback to display the packet elimination on last output port
|
||||
net5_3->TraceConnectWithoutContext("FrerDrop", MakeBoundCallback(&FrerDrop, Names::FindName(net5_3)));
|
||||
|
||||
PcapHelper pcapHelper;
|
||||
std::string pcapFilename;
|
||||
std::string prefix = "example";
|
||||
Ptr<PcapFileWrapper> file;
|
||||
pcapFilename = pcapHelper.GetFilenameFromDevice(prefix, net2_2);
|
||||
file = pcapHelper.CreateFile(pcapFilename, std::ios::out, PcapHelper::DLT_EN10MB);
|
||||
pcapHelper.HookDefaultSink<EthernetNetDevice>(net2_2, "Sniffer", file);
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(MilliSeconds(50));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
285
contrib/tsn/examples/tsn-switched-withFRERonES-aggregation.cc
Normal file
285
contrib/tsn/examples/tsn-switched-withFRERonES-aggregation.cc
Normal file
@@ -0,0 +1,285 @@
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/applications-module.h"
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/drop-tail-queue.h"
|
||||
|
||||
#include "ns3/tsn-node.h"
|
||||
#include "ns3/tsn-net-device.h"
|
||||
#include "ns3/tsn-aggregated-net-device.h"
|
||||
#include "ns3/switch-net-device.h"
|
||||
#include "ns3/ethernet-channel.h"
|
||||
#include "ns3/ethernet-generator.h"
|
||||
#include "ns3/ethernet-header2.h"
|
||||
#include "ns3/stream-identification-function.h"
|
||||
#include "ns3/stream-identification-function-null.h"
|
||||
#include "ns3/frer-sequence-generation-function.h"
|
||||
#include "ns3/frer-sequence-recovery-function.h"
|
||||
#include "ns3/frer-latent-error-detection-function.h"
|
||||
#include "ns3/frer-match-recovery-function.h"
|
||||
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example with 2ES connected 2SW in a 1Gb/s full duplex link to demonstrate
|
||||
* FRER usage when replication and elimation are done on the ES. To be more
|
||||
* specific this example use the ESsource to do the replication using mulitcast
|
||||
* and ESdest to do the elimination. The stream identification is
|
||||
* done by the null stream identification function. The match recovery function,
|
||||
* latent error detection function are also used in this example.
|
||||
* Two flows go from ESsource to ESdest. Only the VLAN 100 flow use FRER mechanisms.
|
||||
*
|
||||
* / ==== SW1 ==== \
|
||||
* ESsource ESdest
|
||||
* \ ==== SW2 ==== /
|
||||
*
|
||||
* Although mutliple ways of implementing elimination and replication on ES are
|
||||
* describe in the standard (IEEE802.1CB-2017 - Annex C), here we implement the
|
||||
* one describe in "IEEE802.1CB-2017 - Annex C - C.1 Example 1: End-to-end FRER"
|
||||
* . This ways is based on the use of IEEE802.1AX for port aggregation.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("Example");
|
||||
|
||||
//A callback to log the pkt reception
|
||||
static void
|
||||
MacRxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
Ptr<Packet> originalPacket = p->Copy();
|
||||
EthernetHeader2 ethHeader;
|
||||
originalPacket->RemoveHeader(ethHeader);
|
||||
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " (VID:" << ethHeader.GetVid() << ") received !");
|
||||
}
|
||||
|
||||
//A callback to log the pkt emission
|
||||
static void
|
||||
PhyTxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
Ptr<Packet> originalPacket = p->Copy();
|
||||
EthernetHeader2 ethHeader;
|
||||
originalPacket->RemoveHeader(ethHeader);
|
||||
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " (VID:" << ethHeader.GetVid() << ") begin transmission !");
|
||||
}
|
||||
|
||||
//A callback to log pkt elimination
|
||||
static void
|
||||
FrerDrop(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
NS_LOG_INFO(context << " : An instance of Packet #"<< p->GetUid() <<" was dropped by FRER recovery function");
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
//Enable logging
|
||||
LogComponentEnable("Example", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("EthernetGenerator", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("TsnAggregatedNetDevice", LOG_LEVEL_INFO);
|
||||
|
||||
CommandLine cmd(__FILE__);
|
||||
cmd.Parse(argc, argv);
|
||||
|
||||
//Create six nodes
|
||||
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
|
||||
Names::Add("ESsource", n0);
|
||||
|
||||
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
|
||||
Names::Add("ESdest", n1);
|
||||
|
||||
Ptr<TsnNode> n2 = CreateObject<TsnNode>();
|
||||
Names::Add("SW1", n2);
|
||||
Ptr<TsnNode> n3 = CreateObject<TsnNode>();
|
||||
Names::Add("SW2", n3);
|
||||
|
||||
//Create and add a netDevices to each node
|
||||
Ptr<TsnNetDevice> n0_net0 = CreateObject<TsnNetDevice>();
|
||||
n0->AddDevice(n0_net0);
|
||||
Names::Add("ESsource#01", n0_net0);
|
||||
Ptr<TsnNetDevice> n0_net1 = CreateObject<TsnNetDevice>();
|
||||
n0->AddDevice(n0_net1);
|
||||
Names::Add("ESsource#02", n0_net1);
|
||||
Ptr<TsnAggregatedNetDevice> n0_netagg = CreateObject<TsnAggregatedNetDevice>();
|
||||
n0_netagg->AddNetDevice(n0_net0);
|
||||
n0_netagg->AddNetDevice(n0_net1);
|
||||
n0->AddDevice(n0_netagg);
|
||||
|
||||
Ptr<TsnNetDevice> n1_net0 = CreateObject<TsnNetDevice>();
|
||||
n1->AddDevice(n1_net0);
|
||||
Names::Add("ESdest#01", n1_net0);
|
||||
Ptr<TsnNetDevice> n1_net1 = CreateObject<TsnNetDevice>();
|
||||
n1->AddDevice(n1_net1);
|
||||
Names::Add("ESdest#02", n1_net1);
|
||||
Ptr<TsnAggregatedNetDevice> n1_netagg = CreateObject<TsnAggregatedNetDevice>();
|
||||
n1_netagg->AddNetDevice(n1_net0);
|
||||
n1_netagg->AddNetDevice(n1_net1);
|
||||
n1->AddDevice(n1_netagg);
|
||||
|
||||
Ptr<TsnNetDevice> n2_net0 = CreateObject<TsnNetDevice>();
|
||||
n2->AddDevice(n2_net0);
|
||||
Ptr<TsnNetDevice> n2_net1 = CreateObject<TsnNetDevice>();
|
||||
n2->AddDevice(n2_net1);
|
||||
|
||||
Ptr<TsnNetDevice> n3_net0 = CreateObject<TsnNetDevice>();
|
||||
n3->AddDevice(n3_net0);
|
||||
Ptr<TsnNetDevice> n3_net1 = CreateObject<TsnNetDevice>();
|
||||
n3->AddDevice(n3_net1);
|
||||
|
||||
//Create Ethernet Channels and attach it to the netDevices
|
||||
Ptr<EthernetChannel> l0 = CreateObject<EthernetChannel>();
|
||||
l0->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
n0_net0->Attach(l0);
|
||||
n2_net0->Attach(l0);
|
||||
Ptr<EthernetChannel> l1 = CreateObject<EthernetChannel>();
|
||||
l1->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
n2_net1->Attach(l1);
|
||||
n1_net0->Attach(l1);
|
||||
Ptr<EthernetChannel> l2 = CreateObject<EthernetChannel>();
|
||||
l2->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
n0_net1->Attach(l2);
|
||||
n3_net0->Attach(l2);
|
||||
Ptr<EthernetChannel> l3 = CreateObject<EthernetChannel>();
|
||||
l3->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
n3_net1->Attach(l3);
|
||||
n1_net1->Attach(l3);
|
||||
|
||||
//Create and add switche net devices to the switch nodes
|
||||
Ptr<SwitchNetDevice> sw1 = CreateObject<SwitchNetDevice>();
|
||||
sw1->SetAttribute("MinForwardingLatency", TimeValue(MicroSeconds(10)));
|
||||
sw1->SetAttribute("MaxForwardingLatency", TimeValue(MicroSeconds(10)));
|
||||
n2->AddDevice(sw1);
|
||||
sw1->AddSwitchPort(n2_net0);
|
||||
sw1->AddSwitchPort(n2_net1);
|
||||
Ptr<SwitchNetDevice> sw2 = CreateObject<SwitchNetDevice>();
|
||||
sw2->SetAttribute("MinForwardingLatency", TimeValue(MicroSeconds(10)));
|
||||
sw2->SetAttribute("MaxForwardingLatency", TimeValue(MicroSeconds(10)));
|
||||
n3->AddDevice(sw2);
|
||||
sw2->AddSwitchPort(n3_net0);
|
||||
sw2->AddSwitchPort(n3_net1);
|
||||
|
||||
//Allocate a Mac address
|
||||
n0_net0->SetAddress(Mac48Address::Allocate());
|
||||
n0_net1->SetAddress(Mac48Address::Allocate());
|
||||
n1_net0->SetAddress(Mac48Address::Allocate());
|
||||
n1_net1->SetAddress(Mac48Address::Allocate());
|
||||
sw1->SetAddress(Mac48Address::Allocate());
|
||||
sw2->SetAddress(Mac48Address::Allocate());
|
||||
|
||||
//Create and add eight FIFO on each net device
|
||||
for (int i=0; i<8; i++)
|
||||
{
|
||||
n0_net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
n0_net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
n1_net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
n1_net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
|
||||
n2_net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
n2_net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
n3_net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
n3_net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
}
|
||||
|
||||
//Add forwarding table
|
||||
sw1->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 100, {n2_net1});
|
||||
sw2->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 100, {n3_net1});
|
||||
|
||||
sw1->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 101, {n2_net1});
|
||||
|
||||
//Stream Indentification + FRER
|
||||
//On aggregated interface of ESsource
|
||||
//Stream identification
|
||||
Ptr<NullStreamIdentificationFunction> sif0 = CreateObject<NullStreamIdentificationFunction>();
|
||||
uint16_t StreamHandle = 1;
|
||||
sif0->SetAttribute("VlanID", UintegerValue(100));
|
||||
sif0->SetAttribute("Address", AddressValue(Mac48Address("ff:ff:ff:ff:ff:ff")));
|
||||
n0->AddStreamIdentificationFunction(StreamHandle, sif0, {}, {}, {n0_netagg}, {});
|
||||
//Sequencing : Sequence generation
|
||||
Ptr<SequenceGenerationFunction> seqf0 = CreateObject<SequenceGenerationFunction>();
|
||||
seqf0->SetAttribute("Direction", BooleanValue(true)); //out-facing
|
||||
seqf0->SetStreamHandle({StreamHandle});
|
||||
n0->AddSequenceGenerationFunction(seqf0);
|
||||
//Sequence encode
|
||||
Ptr<SequenceEncodeDecodeFunction> seqEnc0 = CreateObject<SequenceEncodeDecodeFunction>();
|
||||
seqEnc0->SetAttribute("Direction", BooleanValue(true)); //out-facing
|
||||
seqEnc0->SetAttribute("Active", BooleanValue(true));
|
||||
seqEnc0->SetStreamHandle({StreamHandle});
|
||||
seqEnc0->SetPort(n0_netagg);
|
||||
n0->AddSequenceEncodeDecodeFunction(seqEnc0);
|
||||
|
||||
// On aggregated interface of ESdest
|
||||
//Stream identification
|
||||
Ptr<NullStreamIdentificationFunction> sif1 = CreateObject<NullStreamIdentificationFunction>();
|
||||
StreamHandle = 1;
|
||||
sif1->SetAttribute("VlanID", UintegerValue(100));
|
||||
sif1->SetAttribute("Address", AddressValue(Mac48Address("ff:ff:ff:ff:ff:ff")));
|
||||
n1->AddStreamIdentificationFunction(StreamHandle, sif1, {n1_netagg}, {}, {}, {});
|
||||
//Sequence Decode
|
||||
Ptr<SequenceEncodeDecodeFunction> seqEnc1 = CreateObject<SequenceEncodeDecodeFunction>();
|
||||
seqEnc1->SetAttribute("Direction", BooleanValue(true)); //out-facing
|
||||
seqEnc1->SetAttribute("Active", BooleanValue(false));
|
||||
seqEnc1->SetStreamHandle({StreamHandle});
|
||||
seqEnc1->SetPort(n1_netagg);
|
||||
n1->AddSequenceEncodeDecodeFunction(seqEnc1);
|
||||
//Sequencing : Sequence recovery
|
||||
Ptr<SequenceRecoveryFunction> seqfreco0 = CreateObject<SequenceRecoveryFunction>();
|
||||
seqfreco0->SetAttribute("Direction", BooleanValue(true)); //out-facing
|
||||
seqfreco0->SetAttribute("TakeNoSequence", BooleanValue(false));
|
||||
seqfreco0->SetAttribute("IndividualRecovery", BooleanValue(false));
|
||||
seqfreco0->SetStreamHandle({StreamHandle});
|
||||
seqfreco0->SetPorts({n1_netagg});
|
||||
n1->AddSequenceRecoveryFunction(seqfreco0);
|
||||
//Sequencing : Sequence recovery : recovery function
|
||||
Ptr<MatchRecoveryFunction> recf0 = CreateObject<MatchRecoveryFunction>();
|
||||
seqfreco0->SetRecoveryFunction(recf0);
|
||||
//Sequencing : Sequence recovery : latent error detection function
|
||||
Ptr<LatentErrorDetectionFunction> latf0 = CreateObject<LatentErrorDetectionFunction>();
|
||||
latf0->SetAttribute("LatentErrorPaths", UintegerValue(2));
|
||||
latf0->SetRecoveryFunction(recf0);
|
||||
seqfreco0->SetLatentErrorDetectionFunction(latf0);
|
||||
|
||||
//Application description
|
||||
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
|
||||
app0->Setup(n0_netagg);
|
||||
app0->SetAttribute("BurstSize", UintegerValue(1));
|
||||
app0->SetAttribute("PayloadSize", UintegerValue(1400));
|
||||
app0->SetAttribute("Period", TimeValue(MilliSeconds(10)));
|
||||
app0->SetAttribute("PCP", UintegerValue(1));
|
||||
app0->SetAttribute("VlanID", UintegerValue(100));
|
||||
n0->AddApplication(app0);
|
||||
app0->SetStartTime(MilliSeconds(0));
|
||||
app0->SetStopTime(MilliSeconds(20));
|
||||
|
||||
Ptr<EthernetGenerator> app1 = CreateObject<EthernetGenerator>();
|
||||
app1->Setup(n0_net0);
|
||||
app1->SetAttribute("BurstSize", UintegerValue(1));
|
||||
app1->SetAttribute("PayloadSize", UintegerValue(1400));
|
||||
app1->SetAttribute("Period", TimeValue(MilliSeconds(20)));
|
||||
app1->SetAttribute("PCP", UintegerValue(0));
|
||||
app1->SetAttribute("VlanID", UintegerValue(101));
|
||||
n0->AddApplication(app1);
|
||||
app1->SetStartTime(Seconds(0));
|
||||
app1->SetStopTime(MilliSeconds(41));
|
||||
|
||||
//Callback to display the packet transmitted and received log
|
||||
Packet::EnablePrinting();
|
||||
n0_net0->TraceConnectWithoutContext("PhyTxBegin", MakeBoundCallback(&PhyTxCallback, Names::FindName(n0) + ":" + Names::FindName(n0_net0)));
|
||||
n0_net1->TraceConnectWithoutContext("PhyTxBegin", MakeBoundCallback(&PhyTxCallback, Names::FindName(n0) + ":" + Names::FindName(n0_net1)));
|
||||
n1_netagg->TraceConnectWithoutContext("MacRx", MakeBoundCallback(&MacRxCallback, Names::FindName(n1) + ":" + Names::FindName(n1_netagg)));
|
||||
|
||||
//Callback to display the packet elimination on last output port
|
||||
n1_netagg->TraceConnectWithoutContext("FrerDrop", MakeBoundCallback(&FrerDrop, Names::FindName(n1_netagg)));
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(MilliSeconds(50));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
324
contrib/tsn/examples/tsn-switched-withFRERonES-integratedSW.cc
Normal file
324
contrib/tsn/examples/tsn-switched-withFRERonES-integratedSW.cc
Normal file
@@ -0,0 +1,324 @@
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/applications-module.h"
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/drop-tail-queue.h"
|
||||
|
||||
#include "ns3/tsn-node.h"
|
||||
#include "ns3/tsn-net-device.h"
|
||||
#include "ns3/switch-net-device.h"
|
||||
#include "ns3/ethernet-channel.h"
|
||||
#include "ns3/ethernet-generator.h"
|
||||
#include "ns3/ethernet-header2.h"
|
||||
#include "ns3/stream-identification-function.h"
|
||||
#include "ns3/stream-identification-function-null.h"
|
||||
#include "ns3/frer-sequence-generation-function.h"
|
||||
#include "ns3/frer-sequence-recovery-function.h"
|
||||
#include "ns3/frer-latent-error-detection-function.h"
|
||||
#include "ns3/frer-match-recovery-function.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example with 2ES connected 2SW in a 1Gb/s full duplex link to demonstrate
|
||||
* FRER usage when replication and elimation are done on the ES. To be more
|
||||
* specific this example use the ESsource to do the replication using mulitcast
|
||||
* and ESdest to do the elimination. The stream identification is
|
||||
* done by the null stream identification function. The match recovery function,
|
||||
* latent error detection function are also used in this example.
|
||||
* Two flows go from ESsource to ESdest. Only the VLAN 100 flow use FRER mechanisms.
|
||||
*
|
||||
* / ==== SW1 ==== \
|
||||
* ESsource ESdest
|
||||
* \ ==== SW2 ==== /
|
||||
*
|
||||
* Although mutliple ways of implementing elimination and replication on ES are
|
||||
* describe in the standard (IEEE802.1CB-2017 - Annex C), here we implement the
|
||||
* one describe in "IEEE802.1CB-2017 - Annex C - C.6 Example 6: Chained two-port
|
||||
* end systems". This ways is based on the use of a 3-port switch integrated
|
||||
* into the ES to interface between the ES and the network as described below
|
||||
*
|
||||
* /===
|
||||
* ES == Integrated SW
|
||||
* \===
|
||||
*/
|
||||
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("Example");
|
||||
|
||||
//A callback to log the pkt reception
|
||||
static void
|
||||
MacRxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
Ptr<Packet> originalPacket = p->Copy();
|
||||
EthernetHeader2 ethHeader;
|
||||
originalPacket->RemoveHeader(ethHeader);
|
||||
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " (VID:" << ethHeader.GetVid() << ") received !");
|
||||
}
|
||||
|
||||
//A callback to log the pkt emission
|
||||
static void
|
||||
PhyTxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
Ptr<Packet> originalPacket = p->Copy();
|
||||
EthernetHeader2 ethHeader;
|
||||
originalPacket->RemoveHeader(ethHeader);
|
||||
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " (VID:" << ethHeader.GetVid() << ") begin transmission !");
|
||||
}
|
||||
|
||||
//A callback to log pkt elimination
|
||||
static void
|
||||
FrerDrop(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
NS_LOG_INFO(context << " : An instance of Packet #"<< p->GetUid() <<" was dropped by FRER recovery function");
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
//Enable logging
|
||||
LogComponentEnable("Example", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("EthernetGenerator", LOG_LEVEL_INFO);
|
||||
|
||||
CommandLine cmd(__FILE__);
|
||||
cmd.Parse(argc, argv);
|
||||
|
||||
//Create six nodes
|
||||
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
|
||||
Names::Add("ESsource", n0);
|
||||
Ptr<TsnNode> n0_SW = CreateObject<TsnNode>();
|
||||
Names::Add("ESsource_SW", n0_SW);
|
||||
|
||||
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
|
||||
Names::Add("ESdest", n1);
|
||||
Ptr<TsnNode> n1_SW = CreateObject<TsnNode>();
|
||||
Names::Add("ESdest_SW", n1_SW);
|
||||
|
||||
Ptr<TsnNode> n2 = CreateObject<TsnNode>();
|
||||
Names::Add("SW1", n2);
|
||||
Ptr<TsnNode> n3 = CreateObject<TsnNode>();
|
||||
Names::Add("SW2", n3);
|
||||
|
||||
//Create and add a netDevices to each node
|
||||
Ptr<TsnNetDevice> n0_net0 = CreateObject<TsnNetDevice>();
|
||||
n0->AddDevice(n0_net0);
|
||||
Names::Add("ESsource#01", n0_net0);
|
||||
|
||||
Ptr<TsnNetDevice> n0_SW_net0 = CreateObject<TsnNetDevice>();
|
||||
n0_SW->AddDevice(n0_SW_net0);
|
||||
Names::Add("ESsource_SW#01", n0_SW_net0);
|
||||
Ptr<TsnNetDevice> n0_SW_net1 = CreateObject<TsnNetDevice>();
|
||||
n0_SW->AddDevice(n0_SW_net1);
|
||||
Names::Add("ESsource_SW#02", n0_SW_net1);
|
||||
Ptr<TsnNetDevice> n0_SW_net2 = CreateObject<TsnNetDevice>();
|
||||
n0_SW->AddDevice(n0_SW_net2);
|
||||
Names::Add("ESsource_SW#03", n0_SW_net2);
|
||||
|
||||
Ptr<TsnNetDevice> n1_net0 = CreateObject<TsnNetDevice>();
|
||||
n1->AddDevice(n1_net0);
|
||||
Names::Add("ESdest#01", n1_net0);
|
||||
|
||||
Ptr<TsnNetDevice> n1_SW_net0 = CreateObject<TsnNetDevice>();
|
||||
n1_SW->AddDevice(n1_SW_net0);
|
||||
Names::Add("ESdest_SW#01", n1_SW_net0);
|
||||
Ptr<TsnNetDevice> n1_SW_net1 = CreateObject<TsnNetDevice>();
|
||||
n1_SW->AddDevice(n1_SW_net1);
|
||||
Names::Add("ESdest_SW#02", n1_SW_net1);
|
||||
Ptr<TsnNetDevice> n1_SW_net2 = CreateObject<TsnNetDevice>();
|
||||
n1_SW->AddDevice(n1_SW_net2);
|
||||
Names::Add("ESdest_SW#03", n1_SW_net2);
|
||||
|
||||
Ptr<TsnNetDevice> n2_net0 = CreateObject<TsnNetDevice>();
|
||||
n2->AddDevice(n2_net0);
|
||||
Ptr<TsnNetDevice> n2_net1 = CreateObject<TsnNetDevice>();
|
||||
n2->AddDevice(n2_net1);
|
||||
|
||||
Ptr<TsnNetDevice> n3_net0 = CreateObject<TsnNetDevice>();
|
||||
n3->AddDevice(n3_net0);
|
||||
Ptr<TsnNetDevice> n3_net1 = CreateObject<TsnNetDevice>();
|
||||
n3->AddDevice(n3_net1);
|
||||
|
||||
//Create Ethernet Channels and attach it to the netDevices
|
||||
Ptr<EthernetChannel> l0 = CreateObject<EthernetChannel>();
|
||||
l0->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
n0_net0->Attach(l0);
|
||||
n0_SW_net0->Attach(l0);
|
||||
Ptr<EthernetChannel> l1 = CreateObject<EthernetChannel>();
|
||||
l1->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
n0_SW_net1->Attach(l1);
|
||||
n2_net0->Attach(l1);
|
||||
Ptr<EthernetChannel> l2 = CreateObject<EthernetChannel>();
|
||||
l2->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
n0_SW_net2->Attach(l2);
|
||||
n3_net0->Attach(l2);
|
||||
Ptr<EthernetChannel> l3 = CreateObject<EthernetChannel>();
|
||||
l3->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
n1_net0->Attach(l3);
|
||||
n1_SW_net0->Attach(l3);
|
||||
Ptr<EthernetChannel> l4 = CreateObject<EthernetChannel>();
|
||||
l4->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
n1_SW_net1->Attach(l4);
|
||||
n2_net1->Attach(l4);
|
||||
Ptr<EthernetChannel> l5 = CreateObject<EthernetChannel>();
|
||||
l5->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
n1_SW_net2->Attach(l5);
|
||||
n3_net1->Attach(l5);
|
||||
|
||||
//Create and add switche net devices to the switch nodes
|
||||
Ptr<SwitchNetDevice> n0_SW_sw = CreateObject<SwitchNetDevice>();
|
||||
n0_SW_sw->SetAttribute("MinForwardingLatency", TimeValue(MicroSeconds(0)));
|
||||
n0_SW_sw->SetAttribute("MaxForwardingLatency", TimeValue(MicroSeconds(0)));
|
||||
n0_SW->AddDevice(n0_SW_sw);
|
||||
n0_SW_sw->AddSwitchPort(n0_SW_net0);
|
||||
n0_SW_sw->AddSwitchPort(n0_SW_net1);
|
||||
n0_SW_sw->AddSwitchPort(n0_SW_net2);
|
||||
Ptr<SwitchNetDevice> n1_SW_sw = CreateObject<SwitchNetDevice>();
|
||||
n1_SW_sw->SetAttribute("MinForwardingLatency", TimeValue(MicroSeconds(0)));
|
||||
n1_SW_sw->SetAttribute("MaxForwardingLatency", TimeValue(MicroSeconds(0)));
|
||||
n1_SW->AddDevice(n1_SW_sw);
|
||||
n1_SW_sw->AddSwitchPort(n1_SW_net0);
|
||||
n1_SW_sw->AddSwitchPort(n1_SW_net1);
|
||||
n1_SW_sw->AddSwitchPort(n1_SW_net2);
|
||||
Ptr<SwitchNetDevice> sw1 = CreateObject<SwitchNetDevice>();
|
||||
sw1->SetAttribute("MinForwardingLatency", TimeValue(MicroSeconds(10)));
|
||||
sw1->SetAttribute("MaxForwardingLatency", TimeValue(MicroSeconds(10)));
|
||||
n2->AddDevice(sw1);
|
||||
sw1->AddSwitchPort(n2_net0);
|
||||
sw1->AddSwitchPort(n2_net1);
|
||||
Ptr<SwitchNetDevice> sw2 = CreateObject<SwitchNetDevice>();
|
||||
sw2->SetAttribute("MinForwardingLatency", TimeValue(MicroSeconds(10)));
|
||||
sw2->SetAttribute("MaxForwardingLatency", TimeValue(MicroSeconds(10)));
|
||||
n3->AddDevice(sw2);
|
||||
sw2->AddSwitchPort(n3_net0);
|
||||
sw2->AddSwitchPort(n3_net1);
|
||||
|
||||
//Allocate a Mac address
|
||||
n0_net0->SetAddress(Mac48Address::Allocate());
|
||||
n1_net0->SetAddress(Mac48Address::Allocate());
|
||||
n0_SW_sw->SetAddress(Mac48Address::Allocate());
|
||||
n1_SW_sw->SetAddress(Mac48Address::Allocate());
|
||||
sw1->SetAddress(Mac48Address::Allocate());
|
||||
sw2->SetAddress(Mac48Address::Allocate());
|
||||
|
||||
//Create and add eight FIFO on each net device
|
||||
for (int i=0; i<8; i++)
|
||||
{
|
||||
n0_net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
n0_SW_net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
n0_SW_net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
n0_SW_net2->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
n1_net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
n1_SW_net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
n1_SW_net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
n1_SW_net2->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
n2_net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
n2_net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
n3_net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
n3_net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
}
|
||||
|
||||
//Add forwarding table
|
||||
n0_SW_sw->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 100, {n0_SW_net1, n0_SW_net2});
|
||||
sw1->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 100, {n2_net1});
|
||||
sw2->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 100, {n3_net1});
|
||||
n1_SW_sw->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 100, {n1_SW_net0});
|
||||
|
||||
n0_SW_sw->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 101, {n0_SW_net1});
|
||||
sw1->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 101, {n2_net1});
|
||||
n1_SW_sw->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 101, {n1_SW_net0});
|
||||
|
||||
//Stream Indentification + FRER
|
||||
//Integrated SW on ESsource
|
||||
//Stream identification
|
||||
Ptr<NullStreamIdentificationFunction> sif0 = CreateObject<NullStreamIdentificationFunction>();
|
||||
uint16_t StreamHandle = 1;
|
||||
sif0->SetAttribute("VlanID", UintegerValue(100));
|
||||
sif0->SetAttribute("Address", AddressValue(Mac48Address("ff:ff:ff:ff:ff:ff")));
|
||||
n0_SW->AddStreamIdentificationFunction(StreamHandle, sif0, {n0_SW_net0}, {}, {}, {});
|
||||
//Sequencing : Sequence generation
|
||||
Ptr<SequenceGenerationFunction> seqf0 = CreateObject<SequenceGenerationFunction>();
|
||||
seqf0->SetAttribute("Direction", BooleanValue(false)); //in-facing
|
||||
seqf0->SetStreamHandle({StreamHandle});
|
||||
n0_SW->AddSequenceGenerationFunction(seqf0);
|
||||
//Sequence encode
|
||||
Ptr<SequenceEncodeDecodeFunction> seqEnc0 = CreateObject<SequenceEncodeDecodeFunction>();
|
||||
seqEnc0->SetAttribute("Direction", BooleanValue(false)); //in-facing
|
||||
seqEnc0->SetAttribute("Active", BooleanValue(true));
|
||||
seqEnc0->SetStreamHandle({StreamHandle});
|
||||
seqEnc0->SetPort(n0_SW_net0);
|
||||
n0_SW->AddSequenceEncodeDecodeFunction(seqEnc0);
|
||||
|
||||
//Integrated SW on ESdest
|
||||
//Stream identification
|
||||
Ptr<NullStreamIdentificationFunction> sif1 = CreateObject<NullStreamIdentificationFunction>();
|
||||
StreamHandle = 1;
|
||||
sif1->SetAttribute("VlanID", UintegerValue(100));
|
||||
sif1->SetAttribute("Address", AddressValue(Mac48Address("ff:ff:ff:ff:ff:ff")));
|
||||
n1_SW->AddStreamIdentificationFunction(StreamHandle, sif1, {}, {}, {n1_SW_net0}, {});
|
||||
//Sequence Decode
|
||||
Ptr<SequenceEncodeDecodeFunction> seqEnc1 = CreateObject<SequenceEncodeDecodeFunction>();
|
||||
seqEnc1->SetAttribute("Direction", BooleanValue(false)); //in-facing
|
||||
seqEnc1->SetAttribute("Active", BooleanValue(false));
|
||||
seqEnc1->SetStreamHandle({StreamHandle});
|
||||
seqEnc1->SetPort(n1_SW_net0);
|
||||
n1_SW->AddSequenceEncodeDecodeFunction(seqEnc1);
|
||||
//Sequencing : Sequence recovery
|
||||
Ptr<SequenceRecoveryFunction> seqfreco0 = CreateObject<SequenceRecoveryFunction>();
|
||||
seqfreco0->SetAttribute("Direction", BooleanValue(false)); //in-facing
|
||||
seqfreco0->SetAttribute("TakeNoSequence", BooleanValue(false));
|
||||
seqfreco0->SetAttribute("IndividualRecovery", BooleanValue(false));
|
||||
seqfreco0->SetStreamHandle({StreamHandle});
|
||||
seqfreco0->SetPorts({n1_SW_net0});
|
||||
n1_SW->AddSequenceRecoveryFunction(seqfreco0);
|
||||
//Sequencing : Sequence recovery : recovery function
|
||||
Ptr<MatchRecoveryFunction> recf0 = CreateObject<MatchRecoveryFunction>();
|
||||
seqfreco0->SetRecoveryFunction(recf0);
|
||||
//Sequencing : Sequence recovery : latent error detection function
|
||||
Ptr<LatentErrorDetectionFunction> latf0 = CreateObject<LatentErrorDetectionFunction>();
|
||||
latf0->SetAttribute("LatentErrorPaths", UintegerValue(2));
|
||||
latf0->SetRecoveryFunction(recf0);
|
||||
seqfreco0->SetLatentErrorDetectionFunction(latf0);
|
||||
|
||||
//Application description
|
||||
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
|
||||
app0->Setup(n0_net0);
|
||||
app0->SetAttribute("BurstSize", UintegerValue(1));
|
||||
app0->SetAttribute("PayloadSize", UintegerValue(1400));
|
||||
app0->SetAttribute("Period", TimeValue(MilliSeconds(10)));
|
||||
app0->SetAttribute("PCP", UintegerValue(1));
|
||||
app0->SetAttribute("VlanID", UintegerValue(100));
|
||||
n0->AddApplication(app0);
|
||||
app0->SetStartTime(MilliSeconds(0));
|
||||
app0->SetStopTime(MilliSeconds(20));
|
||||
|
||||
Ptr<EthernetGenerator> app1 = CreateObject<EthernetGenerator>();
|
||||
app1->Setup(n0_net0);
|
||||
app1->SetAttribute("BurstSize", UintegerValue(1));
|
||||
app1->SetAttribute("PayloadSize", UintegerValue(1400));
|
||||
app1->SetAttribute("Period", TimeValue(MilliSeconds(20)));
|
||||
app1->SetAttribute("PCP", UintegerValue(0));
|
||||
app1->SetAttribute("VlanID", UintegerValue(101));
|
||||
n0->AddApplication(app1);
|
||||
app1->SetStartTime(Seconds(0));
|
||||
app1->SetStopTime(MilliSeconds(41));
|
||||
|
||||
//Callback to display the packet transmitted and received log
|
||||
//Packet::EnablePrinting();
|
||||
n0_net0->TraceConnectWithoutContext("PhyTxBegin", MakeBoundCallback(&PhyTxCallback, Names::FindName(n0) + ":" + Names::FindName(n0_net0)));
|
||||
n1_net0->TraceConnectWithoutContext("MacRx", MakeBoundCallback(&MacRxCallback, Names::FindName(n1) + ":" + Names::FindName(n1_net0)));
|
||||
|
||||
//Callback to display the packet elimination on last output port
|
||||
n1_SW_net0->TraceConnectWithoutContext("FrerDrop", MakeBoundCallback(&FrerDrop, Names::FindName(n1_SW_net0)));
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(MilliSeconds(50));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
209
contrib/tsn/examples/tsn-switched-withGPTP.cc
Normal file
209
contrib/tsn/examples/tsn-switched-withGPTP.cc
Normal file
@@ -0,0 +1,209 @@
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/applications-module.h"
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/drop-tail-queue.h"
|
||||
|
||||
#include "ns3/tsn-node.h"
|
||||
#include "ns3/tsn-net-device.h"
|
||||
#include "ns3/switch-net-device.h"
|
||||
#include "ns3/ethernet-channel.h"
|
||||
#include "ns3/clock.h"
|
||||
#include "ns3/clock-constant-drift.h"
|
||||
#include "ns3/gPTP.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example of the use of gPTP on a network composed of three end-stations
|
||||
* and connected by a 1Gb/s full duplex network through a switch. ES1 is the
|
||||
* GPTP Grandmaster.
|
||||
* ES1 === SW1 === ES3
|
||||
* ||
|
||||
* ES2
|
||||
*/
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("Example");
|
||||
|
||||
static void
|
||||
PdelayCallback(std::string context, Ptr<TsnNetDevice> net, double pdelay)
|
||||
{
|
||||
NS_LOG_INFO("[GPTP] At " << Simulator::Now() << " on "<< context << "/" << Names::FindName(net) << " computed pdelay = " << pdelay);
|
||||
}
|
||||
|
||||
static void
|
||||
ClockAfterCorrectionCallback(std::string context, Ptr<Clock> gmClock, Time clockValue)
|
||||
{
|
||||
NS_LOG_INFO("[GPTP] At " << Simulator::Now() << " on "<< context << " clock value after correction = " << clockValue.GetNanoSeconds() << "ns (error = "<< (gmClock->GetLocalTime()-clockValue).GetNanoSeconds() << "ns)");
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
//Enable logging
|
||||
LogComponentEnable("Example", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("TsnNode", LOG_LEVEL_INFO);
|
||||
|
||||
CommandLine cmd(__FILE__);
|
||||
cmd.Parse(argc, argv);
|
||||
|
||||
//Create nodes
|
||||
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
|
||||
Names::Add("ES1", n0);
|
||||
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
|
||||
Names::Add("ES2", n1);
|
||||
Ptr<TsnNode> n2 = CreateObject<TsnNode>();
|
||||
Names::Add("ES3", n2);
|
||||
Ptr<TsnNode> n3 = CreateObject<TsnNode>();
|
||||
Names::Add("SW1", n3);
|
||||
|
||||
|
||||
//Create and add clock to TsnNode
|
||||
Ptr<ConstantDriftClock> c0 = CreateObject<ConstantDriftClock>();
|
||||
c0->SetAttribute("InitialOffset", TimeValue(Seconds(112)));
|
||||
c0->SetAttribute("DriftRate", DoubleValue(-15));
|
||||
c0->SetAttribute("Granularity", TimeValue(NanoSeconds(10)));
|
||||
n0->SetMainClock(c0);
|
||||
|
||||
Ptr<ConstantDriftClock> c1 = CreateObject<ConstantDriftClock>();
|
||||
c1->SetAttribute("InitialOffset", TimeValue(Seconds(3)));
|
||||
c1->SetAttribute("DriftRate", DoubleValue(10));
|
||||
c1->SetAttribute("Granularity", TimeValue(NanoSeconds(10)));
|
||||
n1->SetMainClock(c1);
|
||||
|
||||
Ptr<ConstantDriftClock> c2 = CreateObject<ConstantDriftClock>();
|
||||
c2->SetAttribute("InitialOffset", TimeValue(Seconds(1.5)));
|
||||
c2->SetAttribute("DriftRate", DoubleValue(-8));
|
||||
c2->SetAttribute("Granularity", TimeValue(NanoSeconds(10)));
|
||||
n2->SetMainClock(c2);
|
||||
|
||||
Ptr<ConstantDriftClock> c3 = CreateObject<ConstantDriftClock>();
|
||||
c3->SetAttribute("InitialOffset", TimeValue(Seconds(5)));
|
||||
c3->SetAttribute("DriftRate", DoubleValue(-5));
|
||||
c3->SetAttribute("Granularity", TimeValue(NanoSeconds(10)));
|
||||
n3->SetMainClock(c3);
|
||||
|
||||
|
||||
//Create and add a netDevice to each node
|
||||
Ptr<TsnNetDevice> net0 = CreateObject<TsnNetDevice>();
|
||||
net0->SetAttribute("DataRate", DataRateValue(DataRate("1Gb/s")));
|
||||
n0->AddDevice(net0);
|
||||
Names::Add("ES1#01", net0);
|
||||
Ptr<TsnNetDevice> net1 = CreateObject<TsnNetDevice>();
|
||||
net1->SetAttribute("DataRate", DataRateValue(DataRate("1Gb/s")));
|
||||
n1->AddDevice(net1);
|
||||
Names::Add("ES2#01", net1);
|
||||
Ptr<TsnNetDevice> net2 = CreateObject<TsnNetDevice>();
|
||||
net2->SetAttribute("DataRate", DataRateValue(DataRate("1Gb/s")));
|
||||
n2->AddDevice(net2);
|
||||
Names::Add("ES3#01", net2);
|
||||
|
||||
Ptr<TsnNetDevice> net3_0 = CreateObject<TsnNetDevice>();
|
||||
net3_0->SetAttribute("DataRate", DataRateValue(DataRate("1Gb/s")));
|
||||
n3->AddDevice(net3_0);
|
||||
Names::Add("SW1#01", net3_0);
|
||||
Ptr<TsnNetDevice> net3_1 = CreateObject<TsnNetDevice>();
|
||||
net3_1->SetAttribute("DataRate", DataRateValue(DataRate("1Gb/s")));
|
||||
n3->AddDevice(net3_1);
|
||||
Names::Add("SW1#02", net3_1);
|
||||
Ptr<TsnNetDevice> net3_2 = CreateObject<TsnNetDevice>();
|
||||
net3_2->SetAttribute("DataRate", DataRateValue(DataRate("1Gb/s")));
|
||||
n3->AddDevice(net3_2);
|
||||
Names::Add("SW1#03", net3_2);
|
||||
|
||||
//Create and add a switch net device to the switch node
|
||||
Ptr<SwitchNetDevice> sw = CreateObject<SwitchNetDevice>();
|
||||
sw->SetAttribute("MinForwardingLatency", TimeValue(MicroSeconds(10)));
|
||||
sw->SetAttribute("MaxForwardingLatency", TimeValue(MicroSeconds(10)));
|
||||
n3->AddDevice(sw);
|
||||
sw->AddSwitchPort(net3_0);
|
||||
sw->AddSwitchPort(net3_1);
|
||||
sw->AddSwitchPort(net3_2);
|
||||
|
||||
//Create Ethernet Channel and attach it two the netDevices
|
||||
Ptr<EthernetChannel> l0 = CreateObject<EthernetChannel>();
|
||||
l0->SetAttribute("Delay", TimeValue(Time(NanoSeconds(200))));
|
||||
net0->Attach(l0);
|
||||
net3_0->Attach(l0);
|
||||
Ptr<EthernetChannel> l1 = CreateObject<EthernetChannel>();
|
||||
l1->SetAttribute("Delay", TimeValue(Time(NanoSeconds(200))));
|
||||
net1->Attach(l1);
|
||||
net3_1->Attach(l1);
|
||||
Ptr<EthernetChannel> l2 = CreateObject<EthernetChannel>();
|
||||
l2->SetAttribute("Delay", TimeValue(Time(NanoSeconds(200))));
|
||||
net2->Attach(l2);
|
||||
net3_2->Attach(l2);
|
||||
|
||||
//Allocate a Mac address
|
||||
net0->SetAddress(Mac48Address::Allocate());
|
||||
net1->SetAddress(Mac48Address::Allocate());
|
||||
net2->SetAddress(Mac48Address::Allocate());
|
||||
sw->SetAddress(Mac48Address::Allocate());
|
||||
net3_0->SetAddress(Mac48Address::Allocate());
|
||||
net3_1->SetAddress(Mac48Address::Allocate());
|
||||
net3_2->SetAddress(Mac48Address::Allocate());
|
||||
|
||||
//Add one fifo per netdevice.
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net2->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net3_0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net3_1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net3_2->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
|
||||
//Add and configure GPTP
|
||||
Ptr<GPTP> gPTP0 = CreateObject<GPTP>();
|
||||
gPTP0->SetNode(n0);
|
||||
gPTP0->SetMainClock(c0);
|
||||
gPTP0->AddDomain(0);
|
||||
gPTP0->AddPort(net0, GPTP::MASTER, 0);
|
||||
gPTP0->SetAttribute("SyncInterval", TimeValue(Seconds(0.125))); //This line is not mandatory because 0.125s is the default value
|
||||
gPTP0->SetAttribute("PdelayInterval", TimeValue(Seconds(1))); //This line is not mandatory because 1s is the default value
|
||||
gPTP0->SetAttribute("Priority", UintegerValue(0));
|
||||
n0->AddApplication(gPTP0);
|
||||
gPTP0->SetStartTime(Seconds(0));
|
||||
|
||||
Ptr<GPTP> gPTP1 = CreateObject<GPTP>();
|
||||
gPTP1->SetNode(n1);
|
||||
gPTP1->SetMainClock(c1);
|
||||
gPTP1->AddDomain(0);
|
||||
gPTP1->AddPort(net1, GPTP::SLAVE, 0);
|
||||
gPTP1->SetAttribute("Priority", UintegerValue(0));
|
||||
n1->AddApplication(gPTP1);
|
||||
gPTP1->SetStartTime(Seconds(0));
|
||||
|
||||
Ptr<GPTP> gPTP2 = CreateObject<GPTP>();
|
||||
gPTP2->SetNode(n2);
|
||||
gPTP2->SetMainClock(c2);
|
||||
gPTP2->AddDomain(0);
|
||||
gPTP2->AddPort(net2, GPTP::SLAVE, 0);
|
||||
gPTP2->SetAttribute("Priority", UintegerValue(0));
|
||||
n2->AddApplication(gPTP2);
|
||||
gPTP2->SetStartTime(Seconds(0));
|
||||
|
||||
Ptr<GPTP> gPTP3 = CreateObject<GPTP>();
|
||||
gPTP3->SetNode(n3);
|
||||
gPTP3->SetMainClock(c3);
|
||||
gPTP3->AddDomain(0);
|
||||
gPTP3->AddPort(net3_0, GPTP::SLAVE, 0);
|
||||
gPTP3->AddPort(net3_1, GPTP::MASTER, 0);
|
||||
gPTP3->AddPort(net3_2, GPTP::MASTER, 0);
|
||||
gPTP3->SetAttribute("Priority", UintegerValue(0));
|
||||
n3->AddApplication(gPTP3);
|
||||
gPTP3->SetStartTime(Seconds(0));
|
||||
|
||||
//Callback to displa information about GPTP execution
|
||||
gPTP1->TraceConnectWithoutContext("Pdelay", MakeBoundCallback(&PdelayCallback, Names::FindName(n1)));
|
||||
gPTP3->TraceConnectWithoutContext("Pdelay", MakeBoundCallback(&PdelayCallback, Names::FindName(n3)));
|
||||
gPTP1->TraceConnectWithoutContext("ClockAfterCorrection", MakeBoundCallback(&ClockAfterCorrectionCallback, Names::FindName(n1), c0));
|
||||
gPTP3->TraceConnectWithoutContext("ClockAfterCorrection", MakeBoundCallback(&ClockAfterCorrectionCallback, Names::FindName(n3), c0));
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(Seconds(3));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
8
contrib/tsn/helper/tsn-helper.cc
Normal file
8
contrib/tsn/helper/tsn-helper.cc
Normal file
@@ -0,0 +1,8 @@
|
||||
#include "tsn-helper.h"
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
/* ... */
|
||||
|
||||
}
|
||||
16
contrib/tsn/helper/tsn-helper.h
Normal file
16
contrib/tsn/helper/tsn-helper.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifndef TSN_HELPER_H
|
||||
#define TSN_HELPER_H
|
||||
|
||||
//#include "ns3/tsn.h"
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
// Each class should be documented using Doxygen,
|
||||
// and have an \ingroup tsn directive
|
||||
|
||||
/* ... */
|
||||
|
||||
}
|
||||
|
||||
#endif /* TSN_HELPER_H */
|
||||
177
contrib/tsn/model/cbs.cc
Normal file
177
contrib/tsn/model/cbs.cc
Normal file
@@ -0,0 +1,177 @@
|
||||
#include "cbs.h"
|
||||
#include "ns3/tsn-transmission-selection-algo.h"
|
||||
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/nstime.h"
|
||||
#include "ns3/uinteger.h"
|
||||
#include "ns3/data-rate.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/traced-callback.h"
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("Cbs");
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED(Cbs);
|
||||
|
||||
TypeId
|
||||
Cbs::GetTypeId()
|
||||
{
|
||||
static TypeId tid =
|
||||
TypeId("ns3::Cbs")
|
||||
.SetParent<TsnTransmissionSelectionAlgo>()
|
||||
.SetGroupName("Tsn")
|
||||
.AddConstructor<Cbs>()
|
||||
.AddAttribute("IdleSlope",
|
||||
"CBS idle slope parameter in bit/s",
|
||||
DataRateValue(DataRate("1Gb/s")),
|
||||
MakeDataRateAccessor(&Cbs::m_idleSlope),
|
||||
MakeDataRateChecker())
|
||||
.AddAttribute("portTransmitRate",
|
||||
"CBS port transmit rate parameter in bit/s",
|
||||
DataRateValue(DataRate("1Gb/s")),
|
||||
MakeDataRateAccessor(&Cbs::m_portTransmitRate),
|
||||
MakeDataRateChecker())
|
||||
.AddTraceSource("Credit",
|
||||
"CBS credit",
|
||||
MakeTraceSourceAccessor(&Cbs::m_creditTrace),
|
||||
"ns3::TracedValueCallback::double")
|
||||
.AddAttribute("MaxIdleSlope",
|
||||
"CBS idle slope parameter in bit/s",
|
||||
DataRateValue(DataRate("1000Gb/s")),
|
||||
MakeDataRateAccessor(&Cbs::m_maxIdleSlope),
|
||||
MakeDataRateChecker());
|
||||
return tid;
|
||||
}
|
||||
|
||||
Cbs::Cbs()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
m_credit = 0;
|
||||
m_state = IDLE;
|
||||
m_transmissionGateIsOpen = true;
|
||||
m_lastUpdateCreditTime = Simulator::Now();
|
||||
}
|
||||
|
||||
Cbs::~Cbs()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
}
|
||||
|
||||
bool
|
||||
Cbs::IsReadyToTransmit()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
if(m_credit>=0){
|
||||
if (m_state==WAITING){
|
||||
UpdateCredit(false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else{
|
||||
m_state = WAITING;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Cbs::UpdateCredit(bool trigger_cb)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
NS_ASSERT_MSG(m_idleSlope < m_maxIdleSlope, "Trying to use an idleSlope higher than " << m_maxIdleSlope << ".");
|
||||
|
||||
Time sinceLastCreditUpdate = Simulator::Now() - m_lastUpdateCreditTime;
|
||||
NS_LOG_INFO(sinceLastCreditUpdate);
|
||||
NS_LOG_INFO("State = " << m_state);
|
||||
if(m_transmissionGateIsOpen){
|
||||
if(m_state == WAITING)
|
||||
{
|
||||
m_credit = m_credit + sinceLastCreditUpdate.GetSeconds() * m_idleSlope.GetBitRate();
|
||||
}
|
||||
else if(m_state == IDLE)
|
||||
{
|
||||
double newCredit = m_credit + sinceLastCreditUpdate.GetSeconds() * m_idleSlope.GetBitRate();
|
||||
if(newCredit>=0)
|
||||
{
|
||||
m_creditTrace(m_credit); //Hit the trace before reseting for nicer plot
|
||||
m_credit = 0;
|
||||
}
|
||||
else if(newCredit<0)
|
||||
{
|
||||
m_credit = newCredit;
|
||||
}
|
||||
}
|
||||
}
|
||||
m_creditTrace(m_credit);
|
||||
|
||||
m_lastUpdateCreditTime = Simulator::Now();
|
||||
if(m_credit < 0 && m_transmissionGateIsOpen){
|
||||
Time nextUdpateDelay = Time(Seconds((-m_credit/m_idleSlope.GetBitRate())));
|
||||
NS_LOG_INFO("Now " << m_lastUpdateCreditTime.GetNanoSeconds());
|
||||
NS_LOG_INFO("Next update in " << nextUdpateDelay.GetNanoSeconds());
|
||||
NS_LOG_INFO("Credit : " << m_credit << "\n");
|
||||
if(Time::GetResolution()==Time::NS and nextUdpateDelay.GetNanoSeconds()==0)
|
||||
{
|
||||
//To solve infinit event schedule due to rounding error
|
||||
nextUdpateDelay = Time(NanoSeconds(1));
|
||||
}
|
||||
else if(Time::GetResolution()==Time::PS and nextUdpateDelay.GetPicoSeconds()==0)
|
||||
{
|
||||
//To solve infinit event schedule due to rounding error
|
||||
nextUdpateDelay = Time(PicoSeconds(1));
|
||||
}
|
||||
Simulator::Cancel(m_NextCreditUpdate);
|
||||
m_NextCreditUpdate = Simulator::Schedule(nextUdpateDelay, &Cbs::UpdateCredit, this, true);
|
||||
}
|
||||
|
||||
if(trigger_cb && m_credit >= 0 && m_state==WAITING)
|
||||
{
|
||||
NS_ASSERT_MSG (m_net != nullptr, "NetDevice not set in CBS. Use cbs->SetTsnNetDevice(net);");
|
||||
if (!m_MultidropMode)
|
||||
{
|
||||
ReadyToTransmitCallback();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Cbs::TransmitStart(Ptr<Packet> p, Time txTime)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
m_state = TRANSMITTING;
|
||||
UpdateCredit(true);
|
||||
}
|
||||
|
||||
void
|
||||
Cbs::TransmitComplete(Ptr<Packet> p)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
if (m_queue->IsEmpty()){
|
||||
m_state = IDLE;
|
||||
}
|
||||
else{
|
||||
m_state = WAITING;
|
||||
}
|
||||
int64_t sendSlope = m_idleSlope.GetBitRate() - m_portTransmitRate.GetBitRate();
|
||||
Time sinceLastCreditUpdate = Simulator::Now() - m_lastUpdateCreditTime;
|
||||
m_credit = m_credit + sendSlope*sinceLastCreditUpdate.GetSeconds();
|
||||
m_lastUpdateCreditTime = Simulator::Now();
|
||||
UpdateCredit(true);
|
||||
}
|
||||
|
||||
void
|
||||
Cbs::UpdateTransmissionGate(bool IsOpen)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
UpdateCredit(true);
|
||||
m_transmissionGateIsOpen = IsOpen;
|
||||
UpdateCredit(true);
|
||||
|
||||
if (not IsOpen)
|
||||
{
|
||||
Simulator::Cancel(m_NextCreditUpdate);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
74
contrib/tsn/model/cbs.h
Normal file
74
contrib/tsn/model/cbs.h
Normal file
@@ -0,0 +1,74 @@
|
||||
#ifndef CBS_H
|
||||
#define CBS_H
|
||||
|
||||
#include "ns3/tsn-transmission-selection-algo.h"
|
||||
|
||||
#include "ns3/data-rate.h"
|
||||
#include "ns3/traced-callback.h"
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
class Cbs: public TsnTransmissionSelectionAlgo
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \brief Get the TypeId
|
||||
*
|
||||
* \return The TypeId for this class
|
||||
*/
|
||||
static TypeId GetTypeId();
|
||||
|
||||
/**
|
||||
* \brief Create a Cbs
|
||||
*/
|
||||
Cbs();
|
||||
|
||||
/**
|
||||
* Destroy a Cbs
|
||||
*
|
||||
* This is the destructor for the Cbs.
|
||||
*/
|
||||
~Cbs();
|
||||
|
||||
// Delete copy constructor and assignment operator to avoid misuse
|
||||
Cbs& operator=(const Cbs&) = delete;
|
||||
Cbs(const Cbs&) = delete;
|
||||
|
||||
|
||||
bool IsReadyToTransmit() override;
|
||||
void TransmitStart(Ptr<Packet> p, Time txTime) override;
|
||||
void TransmitComplete(Ptr<Packet> p) override;
|
||||
void UpdateTransmissionGate(bool IsOpen) override;
|
||||
|
||||
|
||||
TracedCallback<double> m_creditTrace;
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
void UpdateCredit(bool trigger_cb);
|
||||
|
||||
DataRate m_idleSlope;
|
||||
DataRate m_maxIdleSlope;
|
||||
DataRate m_portTransmitRate;
|
||||
double m_credit;
|
||||
Time m_lastUpdateCreditTime;
|
||||
EventId m_NextCreditUpdate;
|
||||
|
||||
|
||||
enum State
|
||||
{
|
||||
/** Idle with no pkt in the FIFO */
|
||||
IDLE,
|
||||
/** Transmitting a packet */
|
||||
TRANSMITTING,
|
||||
/** Waiting with at least one pkt in the FIFO */
|
||||
WAITING,
|
||||
};
|
||||
|
||||
State m_state;
|
||||
};
|
||||
|
||||
}
|
||||
#endif /* CBS_H */
|
||||
106
contrib/tsn/model/clock-constant-drift.cc
Normal file
106
contrib/tsn/model/clock-constant-drift.cc
Normal file
@@ -0,0 +1,106 @@
|
||||
#include "clock-constant-drift.h"
|
||||
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/uinteger.h"
|
||||
#include <ns3/double.h>
|
||||
|
||||
#include "ns3/clock.h"
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("ConstantDriftClock");
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED(ConstantDriftClock);
|
||||
|
||||
TypeId
|
||||
ConstantDriftClock::GetTypeId()
|
||||
{
|
||||
static TypeId tid =
|
||||
TypeId("ns3::ConstantDriftClock")
|
||||
.SetParent<Clock>()
|
||||
.SetGroupName("tsn")
|
||||
.AddConstructor<ConstantDriftClock>()
|
||||
.AddAttribute("InitialOffset",
|
||||
"Initial clock offset",
|
||||
TimeValue(Time(0)),
|
||||
MakeTimeAccessor(&ConstantDriftClock::m_initialOffset),
|
||||
MakeTimeChecker())
|
||||
.AddAttribute("DriftRate",
|
||||
"Clock drift rate in ppm",
|
||||
DoubleValue(0),
|
||||
MakeDoubleAccessor(&ConstantDriftClock::m_driftRate),
|
||||
MakeDoubleChecker<double>());
|
||||
return tid;
|
||||
}
|
||||
|
||||
|
||||
ConstantDriftClock::ConstantDriftClock()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
}
|
||||
|
||||
ConstantDriftClock::~ConstantDriftClock()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
}
|
||||
|
||||
void
|
||||
ConstantDriftClock::UpdateTime()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
if(!m_IsInitialised)
|
||||
{
|
||||
m_lastUpdateTimeValue = m_initialOffset;
|
||||
m_IsInitialised = true;
|
||||
}
|
||||
|
||||
Time durationSinceLastUpdate = Simulator::Now() - m_lastUpdateTime;
|
||||
|
||||
uint64_t t = (m_lastUpdateTimeValue + durationSinceLastUpdate + durationSinceLastUpdate * m_driftRate * pow(10,-6)).GetNanoSeconds();
|
||||
Time tmp = Time(NanoSeconds( (t/m_granularity.GetNanoSeconds()) * m_granularity.GetNanoSeconds()));
|
||||
if(m_lastUpdateTimeValue != tmp)
|
||||
{
|
||||
m_lastUpdateTimeValue = tmp;
|
||||
m_lastUpdateTime = Simulator::Now();
|
||||
}
|
||||
}
|
||||
|
||||
Time
|
||||
ConstantDriftClock::GetLocalTime()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
return GetUncorrectedLocalTime() + m_correctionOffset;
|
||||
}
|
||||
|
||||
Time
|
||||
ConstantDriftClock::GetUncorrectedLocalTime()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
UpdateTime();
|
||||
return m_lastUpdateTimeValue;
|
||||
}
|
||||
|
||||
Time
|
||||
ConstantDriftClock::GetTimeAt(Time t)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
UpdateTime();
|
||||
Time duration = t - m_lastUpdateTime;
|
||||
uint64_t tmp = (m_lastUpdateTimeValue + duration + duration * m_driftRate * pow(10,-6)).GetNanoSeconds();
|
||||
return m_correctionOffset + Time(NanoSeconds( (tmp/m_granularity.GetNanoSeconds()) * m_granularity.GetNanoSeconds()));
|
||||
|
||||
}
|
||||
|
||||
Time
|
||||
ConstantDriftClock::GetDuration(Time d)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
uint64_t tmp = (d/(m_driftRate * pow(10,-6) + 1)).GetNanoSeconds();
|
||||
return Time(NanoSeconds( (1 + tmp/m_granularity.GetNanoSeconds()) * m_granularity.GetNanoSeconds()));
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
56
contrib/tsn/model/clock-constant-drift.h
Normal file
56
contrib/tsn/model/clock-constant-drift.h
Normal file
@@ -0,0 +1,56 @@
|
||||
#ifndef CONSTANTDRIFTCLOCK_H
|
||||
#define CONSTANTDRIFTCLOCK_H
|
||||
|
||||
#include "ns3/object.h"
|
||||
#include "ns3/nstime.h"
|
||||
|
||||
#include "ns3/clock.h"
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
class ConstantDriftClock: public Clock
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \brief Get the TypeId
|
||||
*
|
||||
* \return The TypeId for this class
|
||||
*/
|
||||
static TypeId GetTypeId();
|
||||
|
||||
/**
|
||||
* \brief Create a ConstantDriftClock
|
||||
*/
|
||||
ConstantDriftClock();
|
||||
|
||||
/**
|
||||
* Destroy a ConstantDriftClock
|
||||
*
|
||||
* This is the destructor for the ConstantDriftClock.
|
||||
*/
|
||||
~ConstantDriftClock() override;
|
||||
|
||||
// Delete copy constructor and assignment operator to avoid misuse
|
||||
ConstantDriftClock& operator=(const ConstantDriftClock&) = delete;
|
||||
ConstantDriftClock(const ConstantDriftClock&) = delete;
|
||||
|
||||
Time GetLocalTime() override;
|
||||
Time GetUncorrectedLocalTime() override;
|
||||
Time GetTimeAt(Time t) override;
|
||||
Time GetDuration(Time t) override;
|
||||
void UpdateTime() override;
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
Time m_initialOffset;
|
||||
bool m_IsInitialised = false;
|
||||
Time m_lastUpdateTime;
|
||||
Time m_lastUpdateTimeValue;
|
||||
double m_driftRate;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
#endif /* CONSTANTDRIFTCLOCK_H */
|
||||
83
contrib/tsn/model/clock-fix-precision.cc
Normal file
83
contrib/tsn/model/clock-fix-precision.cc
Normal file
@@ -0,0 +1,83 @@
|
||||
#include "clock-fix-precision.h"
|
||||
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/uinteger.h"
|
||||
#include <ns3/double.h>
|
||||
|
||||
#include "ns3/clock.h"
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("FixPrecisionClock");
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED(FixPrecisionClock);
|
||||
|
||||
TypeId
|
||||
FixPrecisionClock::GetTypeId()
|
||||
{
|
||||
static TypeId tid =
|
||||
TypeId("ns3::FixPrecisionClock")
|
||||
.SetParent<Clock>()
|
||||
.SetGroupName("tsn")
|
||||
.AddConstructor<FixPrecisionClock>()
|
||||
.AddAttribute("Precision",
|
||||
"Fix precision offset according to the reference clock (i.e. GM)",
|
||||
TimeValue(Time(0)),
|
||||
MakeTimeAccessor(&FixPrecisionClock::m_precision),
|
||||
MakeTimeChecker());
|
||||
return tid;
|
||||
}
|
||||
|
||||
|
||||
FixPrecisionClock::FixPrecisionClock()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
}
|
||||
|
||||
FixPrecisionClock::~FixPrecisionClock()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
}
|
||||
|
||||
void
|
||||
FixPrecisionClock::SetRefClock(Ptr<Clock> refClock)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
m_refClock = refClock;
|
||||
}
|
||||
|
||||
Time
|
||||
FixPrecisionClock::GetLocalTime()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
return GetUncorrectedLocalTime() + m_precision;
|
||||
}
|
||||
|
||||
Time
|
||||
FixPrecisionClock::GetUncorrectedLocalTime()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
|
||||
NS_ASSERT_MSG(m_refClock != nullptr,
|
||||
"Reference clock no set using void VirtualClock::SetRefClock(Ptr<Clock> refClock)");
|
||||
return m_refClock->GetUncorrectedLocalTime();
|
||||
}
|
||||
|
||||
Time
|
||||
FixPrecisionClock::GetTimeAt(Time t)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
return m_precision + m_refClock->GetTimeAt(t);
|
||||
}
|
||||
|
||||
Time
|
||||
FixPrecisionClock::GetDuration(Time d)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
return m_refClock->GetDuration(d);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
64
contrib/tsn/model/clock-fix-precision.h
Normal file
64
contrib/tsn/model/clock-fix-precision.h
Normal file
@@ -0,0 +1,64 @@
|
||||
#ifndef FIXPRECISIONCLOCK_H
|
||||
#define FIXPRECISIONCLOCK_H
|
||||
|
||||
#include "ns3/object.h"
|
||||
#include "ns3/nstime.h"
|
||||
|
||||
#include "ns3/clock.h"
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
/**
|
||||
* \ingroup tsn
|
||||
* \brief Clock with fix precision.
|
||||
*
|
||||
* This class represents a non realistic clock that have a fix precision
|
||||
* according to the grandmaster time base. It is only use to research purpose
|
||||
* (search of the worst case scenario)
|
||||
*
|
||||
*/
|
||||
class FixPrecisionClock: public Clock
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \brief Get the TypeId
|
||||
*
|
||||
* \return The TypeId for this class
|
||||
*/
|
||||
static TypeId GetTypeId();
|
||||
|
||||
/**
|
||||
* \brief Create a FixPrecisionClock
|
||||
*/
|
||||
FixPrecisionClock();
|
||||
|
||||
/**
|
||||
* Destroy a FixPrecisionClock
|
||||
*
|
||||
* This is the destructor for the FixPrecisionClock.
|
||||
*/
|
||||
~FixPrecisionClock() override;
|
||||
|
||||
// Delete copy constructor and assignment operator to avoid misuse
|
||||
FixPrecisionClock& operator=(const FixPrecisionClock&) = delete;
|
||||
FixPrecisionClock(const FixPrecisionClock&) = delete;
|
||||
|
||||
Time GetLocalTime() override;
|
||||
Time GetUncorrectedLocalTime() override;
|
||||
Time GetTimeAt(Time t) override;
|
||||
Time GetDuration(Time t) override;
|
||||
|
||||
void SetRefClock(Ptr<Clock> refClock);
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
Time m_precision;
|
||||
Ptr<Clock> m_refClock = nullptr;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
#endif /* FIXPRECISIONCLOCK_H */
|
||||
77
contrib/tsn/model/clock-virtual.cc
Normal file
77
contrib/tsn/model/clock-virtual.cc
Normal file
@@ -0,0 +1,77 @@
|
||||
#include "clock-virtual.h"
|
||||
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/uinteger.h"
|
||||
#include <ns3/double.h>
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("VirtualClock");
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED(VirtualClock);
|
||||
|
||||
TypeId
|
||||
VirtualClock::GetTypeId()
|
||||
{
|
||||
static TypeId tid =
|
||||
TypeId("ns3::VirtualClock")
|
||||
.SetParent<Clock>()
|
||||
.SetGroupName("tsn")
|
||||
.AddConstructor<VirtualClock>();
|
||||
return tid;
|
||||
}
|
||||
|
||||
|
||||
VirtualClock::VirtualClock()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
}
|
||||
|
||||
VirtualClock::~VirtualClock()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
}
|
||||
|
||||
void
|
||||
VirtualClock::SetRefClock(Ptr<Clock> refClock)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
m_refClock = refClock;
|
||||
}
|
||||
|
||||
|
||||
Time
|
||||
VirtualClock::GetLocalTime()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
return GetUncorrectedLocalTime() + m_correctionOffset;
|
||||
}
|
||||
|
||||
Time
|
||||
VirtualClock::GetUncorrectedLocalTime()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
|
||||
NS_ASSERT_MSG(m_refClock != nullptr,
|
||||
"Reference clock no set using void VirtualClock::SetRefClock(Ptr<Clock> refClock)");
|
||||
return m_refClock->GetUncorrectedLocalTime();
|
||||
}
|
||||
|
||||
Time
|
||||
VirtualClock::GetTimeAt(Time t)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
return m_correctionOffset + m_refClock->GetTimeAt(t);
|
||||
}
|
||||
|
||||
Time
|
||||
VirtualClock::GetDuration(Time d)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
return m_refClock->GetDuration(d);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
52
contrib/tsn/model/clock-virtual.h
Normal file
52
contrib/tsn/model/clock-virtual.h
Normal file
@@ -0,0 +1,52 @@
|
||||
#ifndef VIRTUALCLOCK_H
|
||||
#define VIRTUALCLOCK_H
|
||||
|
||||
#include "ns3/object.h"
|
||||
#include "ns3/nstime.h"
|
||||
|
||||
#include "ns3/clock.h"
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
class VirtualClock: public Clock
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \brief Get the TypeId
|
||||
*
|
||||
* \return The TypeId for this class
|
||||
*/
|
||||
static TypeId GetTypeId();
|
||||
|
||||
/**
|
||||
* \brief Create a VirtualClock
|
||||
*/
|
||||
VirtualClock();
|
||||
|
||||
/**
|
||||
* Destroy a VirtualClock
|
||||
*
|
||||
* This is the destructor for the VirtualClock.
|
||||
*/
|
||||
~VirtualClock() override;
|
||||
|
||||
// Delete copy constructor and assignment operator to avoid misuse
|
||||
VirtualClock& operator=(const VirtualClock&) = delete;
|
||||
VirtualClock(const VirtualClock&) = delete;
|
||||
|
||||
Time GetLocalTime() override;
|
||||
Time GetUncorrectedLocalTime() override;
|
||||
Time GetTimeAt(Time t) override;
|
||||
Time GetDuration(Time t) override;
|
||||
void SetRefClock(Ptr<Clock> refClock);
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
Ptr<Clock> m_refClock = nullptr;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
#endif /* VIRTUALCLOCK_H */
|
||||
98
contrib/tsn/model/clock.cc
Normal file
98
contrib/tsn/model/clock.cc
Normal file
@@ -0,0 +1,98 @@
|
||||
#include "clock.h"
|
||||
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/simulator.h"
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("Clock");
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED(Clock);
|
||||
|
||||
TypeId
|
||||
Clock::GetTypeId()
|
||||
{
|
||||
static TypeId tid =
|
||||
TypeId("ns3::Clock")
|
||||
.SetParent<Object>()
|
||||
.SetGroupName("tsn")
|
||||
.AddConstructor<Clock>()
|
||||
.AddAttribute("Granularity",
|
||||
"Clock granularity in ns",
|
||||
TimeValue(Time(NanoSeconds(1))),
|
||||
MakeTimeAccessor(&Clock::m_granularity),
|
||||
MakeTimeChecker());
|
||||
return tid;
|
||||
}
|
||||
|
||||
|
||||
Clock::Clock()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
}
|
||||
|
||||
Clock::~Clock()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
}
|
||||
|
||||
Time
|
||||
Clock::GetLocalTime()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
return GetUncorrectedLocalTime() + m_correctionOffset;
|
||||
}
|
||||
|
||||
Time
|
||||
Clock::GetUncorrectedLocalTime()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
return Simulator::Now();
|
||||
}
|
||||
|
||||
Time
|
||||
Clock::GetTimeAt(Time t)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
return t;
|
||||
}
|
||||
|
||||
Time
|
||||
Clock::GetDuration(Time d)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
return d;
|
||||
}
|
||||
|
||||
void
|
||||
Clock::UpdateTime(){
|
||||
NS_LOG_FUNCTION(this);
|
||||
}
|
||||
|
||||
void
|
||||
Clock::SetOffsetTime(Time offset)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
m_correctionOffset = offset;
|
||||
TriggerCorrectionCallback();
|
||||
}
|
||||
|
||||
void
|
||||
Clock::AddClockCorrectionCallback(Callback<void> cb)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
m_callbacks.insert(m_callbacks.end(), cb);
|
||||
}
|
||||
|
||||
void
|
||||
Clock::TriggerCorrectionCallback()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
for(int i = 0; i < (int)m_callbacks.size(); i++)
|
||||
{
|
||||
m_callbacks[i]();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
70
contrib/tsn/model/clock.h
Normal file
70
contrib/tsn/model/clock.h
Normal file
@@ -0,0 +1,70 @@
|
||||
#ifndef CLOCK_H
|
||||
#define CLOCK_H
|
||||
|
||||
#include "ns3/object.h"
|
||||
#include "ns3/nstime.h"
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
class Clock: public Object
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \brief Get the TypeId
|
||||
*
|
||||
* \return The TypeId for this class
|
||||
*/
|
||||
static TypeId GetTypeId();
|
||||
|
||||
/**
|
||||
* \brief Create a Clock
|
||||
*/
|
||||
Clock();
|
||||
|
||||
/**
|
||||
* Destroy a Clock
|
||||
*
|
||||
* This is the destructor for the Clock.
|
||||
*/
|
||||
~Clock();
|
||||
|
||||
// Delete copy constructor and assignment operator to avoid misuse
|
||||
Clock& operator=(const Clock&) = delete;
|
||||
Clock(const Clock&) = delete;
|
||||
|
||||
void AddClockCorrectionCallback(Callback<void> cb);
|
||||
void TriggerCorrectionCallback();
|
||||
|
||||
virtual Time GetLocalTime();
|
||||
virtual Time GetUncorrectedLocalTime();
|
||||
/**
|
||||
*
|
||||
* \brief Get Clock time at instant t in the simulator/perfect time base
|
||||
*
|
||||
* \params t Timestamp in the simulator/perfect time base
|
||||
* \return clock time at instant t
|
||||
*/
|
||||
virtual Time GetTimeAt(Time t);
|
||||
/**
|
||||
*
|
||||
* \brief Get duration in the clock timebase from duration in the simulator/perfect time base
|
||||
*
|
||||
* \params d duration in the simulator/perfect time base
|
||||
* \return duration in the clock timebase
|
||||
*/
|
||||
virtual Time GetDuration(Time d);
|
||||
virtual void UpdateTime();
|
||||
void SetOffsetTime(Time offset);
|
||||
|
||||
protected:
|
||||
Time m_correctionOffset = Time(0);
|
||||
Time m_granularity;
|
||||
private:
|
||||
|
||||
std::vector<Callback<void>> m_callbacks;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
#endif /* CLOCK_H */
|
||||
82
contrib/tsn/model/frer-base-recovery-function.cc
Normal file
82
contrib/tsn/model/frer-base-recovery-function.cc
Normal file
@@ -0,0 +1,82 @@
|
||||
#include "frer-base-recovery-function.h"
|
||||
|
||||
#include "ns3/log.h"
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("BaseRecoveryFunction");
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED(BaseRecoveryFunction);
|
||||
|
||||
TypeId
|
||||
BaseRecoveryFunction::GetTypeId()
|
||||
{
|
||||
static TypeId tid =
|
||||
TypeId("ns3::BaseRecoveryFunction")
|
||||
.SetParent<Object>()
|
||||
.SetGroupName("tsn")
|
||||
.AddConstructor<BaseRecoveryFunction>()
|
||||
.AddAttribute("ResetTimer",
|
||||
"Reset timer duration for recovery algorithm",
|
||||
TimeValue(MilliSeconds(10000)),
|
||||
MakeTimeAccessor(&BaseRecoveryFunction::m_frerSeqRcvyResetMSec),
|
||||
MakeTimeChecker())
|
||||
.AddAttribute("MinResetTimer",
|
||||
"Min reset timer duration for recovery algorithm",
|
||||
TimeValue(Seconds(0)),
|
||||
MakeTimeAccessor(&BaseRecoveryFunction::m_frerMinSeqRcvyResetMSec),
|
||||
MakeTimeChecker())
|
||||
.AddAttribute("MaxResetTimer",
|
||||
"Max reset timer duration for recovery algorithm",
|
||||
TimeValue(Seconds(65535)),
|
||||
MakeTimeAccessor(&BaseRecoveryFunction::m_frerMaxSeqRcvyResetMSec),
|
||||
MakeTimeChecker());
|
||||
return tid;
|
||||
}
|
||||
|
||||
|
||||
BaseRecoveryFunction::BaseRecoveryFunction()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
}
|
||||
|
||||
BaseRecoveryFunction::~BaseRecoveryFunction()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
}
|
||||
|
||||
|
||||
uint
|
||||
BaseRecoveryFunction::GetFrerCpsSeqRcvyPassedPackets()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
return m_frerCpsSeqRcvyPassedPackets;
|
||||
}
|
||||
|
||||
uint
|
||||
BaseRecoveryFunction::GetFrerCpsSeqRcvyDiscardedPackets()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
return m_frerCpsSeqRcvyDiscardedPackets;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
BaseRecoveryFunction::DoRecovery(uint16_t seqNumber)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
NS_ASSERT_MSG(m_frerSeqRcvyResetMSec >= m_frerMinSeqRcvyResetMSec, "Trying to use a shorter recovery reset timer than " << m_frerMinSeqRcvyResetMSec << ".");
|
||||
NS_ASSERT_MSG(m_frerSeqRcvyResetMSec <= m_frerMaxSeqRcvyResetMSec, "Trying to use a longer recovery reset timer than " << m_frerMaxSeqRcvyResetMSec << ".");
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
BaseRecoveryFunction::resetRecoveryFunction()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
NS_LOG_INFO("Reset FRER recovery function !");
|
||||
m_takeAny = true;
|
||||
}
|
||||
|
||||
}
|
||||
68
contrib/tsn/model/frer-base-recovery-function.h
Normal file
68
contrib/tsn/model/frer-base-recovery-function.h
Normal file
@@ -0,0 +1,68 @@
|
||||
#ifndef FRER_BASE_RECOVERY_FUNCTION_H
|
||||
#define FRER_BASE_RECOVERY_FUNCTION_H
|
||||
|
||||
#include "ns3/object.h"
|
||||
|
||||
#include "ns3/nstime.h"
|
||||
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
class BaseRecoveryFunction : public Object
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \brief Get the TypeId
|
||||
*
|
||||
* \return The TypeId for this class
|
||||
*/
|
||||
static TypeId GetTypeId();
|
||||
|
||||
/**
|
||||
* \brief Create a BaseRecoveryFunction
|
||||
*/
|
||||
BaseRecoveryFunction();
|
||||
|
||||
/**
|
||||
* Destroy a BaseRecoveryFunction
|
||||
*
|
||||
* This is the destructor for the BaseRecoveryFunction.
|
||||
*/
|
||||
~BaseRecoveryFunction();
|
||||
|
||||
// Delete copy constructor and assignment operator to avoid misuse
|
||||
BaseRecoveryFunction& operator=(const BaseRecoveryFunction&) = delete;
|
||||
BaseRecoveryFunction(const BaseRecoveryFunction&) = delete;
|
||||
|
||||
uint GetFrerCpsSeqRcvyPassedPackets();
|
||||
uint GetFrerCpsSeqRcvyDiscardedPackets();
|
||||
|
||||
void resetRecoveryFunction();
|
||||
|
||||
virtual bool DoRecovery(uint16_t seqNumber);
|
||||
|
||||
protected:
|
||||
uint m_recovSeqSpace = 65536; //802.1CB-2017 : 7.4.3.2.1
|
||||
uint16_t m_recovSeqNum = 0; //802.1CB-2017 : 7.4.3.2.3
|
||||
bool m_takeAny = true; //802.1CB-2017 : 7.4.3.2.6
|
||||
Time m_frerSeqRcvyResetMSec; //802.1CB-2017 : 10.4.1.7
|
||||
bool m_frerSeqRcvyIndividualRecovery = false; //802.1CB-2017 : 10.4.1.10
|
||||
|
||||
uint m_frerCpsSeqRcvyOutOfOrderPackets = 0; //802.1CB-2017 : 10.8.3
|
||||
uint m_frerCpsSeqRcvyPassedPackets = 0; //802.1CB-2017 : 10.8.5
|
||||
uint m_frerCpsSeqRcvyDiscardedPackets = 0; //802.1CB-2017 : 10.8.6
|
||||
|
||||
Time m_frerMinSeqRcvyResetMSec;
|
||||
Time m_frerMaxSeqRcvyResetMSec;
|
||||
|
||||
EventId m_resetEvent;
|
||||
|
||||
|
||||
private:
|
||||
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
#endif /* FRER_BASE_RECOVERY_FUNCTION_H */
|
||||
127
contrib/tsn/model/frer-latent-error-detection-function.cc
Normal file
127
contrib/tsn/model/frer-latent-error-detection-function.cc
Normal file
@@ -0,0 +1,127 @@
|
||||
#include "frer-latent-error-detection-function.h"
|
||||
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/uinteger.h"
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("LatentErrorDetectionFunction");
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED(LatentErrorDetectionFunction);
|
||||
|
||||
TypeId
|
||||
LatentErrorDetectionFunction::GetTypeId()
|
||||
{
|
||||
static TypeId tid =
|
||||
TypeId("ns3::LatentErrorDetectionFunction")
|
||||
.SetParent<Object>()
|
||||
.SetGroupName("tsn")
|
||||
.AddConstructor<LatentErrorDetectionFunction>()
|
||||
.AddAttribute("TestTimer",
|
||||
"Test timer duration",
|
||||
TimeValue(Seconds(2)),
|
||||
MakeTimeAccessor(&LatentErrorDetectionFunction::m_frerSeqRcvyLatentErrorPeriod),
|
||||
MakeTimeChecker())
|
||||
.AddAttribute("ResetTimer",
|
||||
"Reset timer duration",
|
||||
TimeValue(Seconds(30)),
|
||||
MakeTimeAccessor(&LatentErrorDetectionFunction::m_frerSeqRcvyLatentResetPeriod),
|
||||
MakeTimeChecker())
|
||||
.AddAttribute("LatentErrorPaths",
|
||||
"Number of Latent Error Paths",
|
||||
UintegerValue(2),
|
||||
MakeUintegerAccessor(&LatentErrorDetectionFunction::m_frerSeqRcvyLatentErrorPaths),
|
||||
MakeUintegerChecker<uint>())
|
||||
.AddAttribute("LatentErrorDifference",
|
||||
"Latent Error Difference threshold",
|
||||
UintegerValue(0),
|
||||
MakeUintegerAccessor(&LatentErrorDetectionFunction::m_frerSeqRcvyLatentErrorDifference),
|
||||
MakeUintegerChecker<uint>())
|
||||
.AddAttribute("MinTestTimer",
|
||||
"Min test timer duration",
|
||||
TimeValue(Seconds(0)),
|
||||
MakeTimeAccessor(&LatentErrorDetectionFunction::m_frerSeqRcvyMinLatentErrorPeriod),
|
||||
MakeTimeChecker())
|
||||
.AddAttribute("MaxTestTimer",
|
||||
"Max test timer duration",
|
||||
TimeValue(Seconds(65535)),
|
||||
MakeTimeAccessor(&LatentErrorDetectionFunction::m_frerSeqRcvyMaxLatentErrorPeriod),
|
||||
MakeTimeChecker())
|
||||
.AddAttribute("MinResetTimer",
|
||||
"Min reset timer duration",
|
||||
TimeValue(Seconds(0)),
|
||||
MakeTimeAccessor(&LatentErrorDetectionFunction::m_frerSeqRcvyMinLatentResetPeriod),
|
||||
MakeTimeChecker())
|
||||
.AddAttribute("MaxResetTimer",
|
||||
"Max reset timer duration",
|
||||
TimeValue(Seconds(65535)),
|
||||
MakeTimeAccessor(&LatentErrorDetectionFunction::m_frerSeqRcvyMaxLatentResetPeriod),
|
||||
MakeTimeChecker());
|
||||
return tid;
|
||||
}
|
||||
|
||||
|
||||
LatentErrorDetectionFunction::LatentErrorDetectionFunction()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
m_resetEvent = Simulator::Schedule(m_frerSeqRcvyLatentResetPeriod, &LatentErrorDetectionFunction::LatentErrorReset, this);
|
||||
m_testEvent = Simulator::Schedule(m_frerSeqRcvyLatentErrorPeriod, &LatentErrorDetectionFunction::LatentErrorTest, this);
|
||||
}
|
||||
|
||||
LatentErrorDetectionFunction::~LatentErrorDetectionFunction()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
}
|
||||
|
||||
void
|
||||
LatentErrorDetectionFunction::SetRecoveryFunction(Ptr<BaseRecoveryFunction> recoveryFunction)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
m_recoveryFunction = recoveryFunction;
|
||||
}
|
||||
|
||||
void
|
||||
LatentErrorDetectionFunction::LatentErrorReset()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
// NS_LOG_INFO("Latent Error Reset ! ");
|
||||
NS_ASSERT_MSG(m_recoveryFunction!=nullptr, "Recovery function not set ...");
|
||||
m_curBaseDifference = (m_recoveryFunction->GetFrerCpsSeqRcvyPassedPackets() *(m_frerSeqRcvyLatentErrorPaths - 1)) - m_recoveryFunction->GetFrerCpsSeqRcvyDiscardedPackets();
|
||||
m_frerCpsSeqRcvyLatentErrorResets += 1;
|
||||
m_resetEvent = Simulator::Schedule(m_frerSeqRcvyLatentResetPeriod, &LatentErrorDetectionFunction::LatentErrorReset, this);
|
||||
}
|
||||
|
||||
void
|
||||
LatentErrorDetectionFunction::LatentErrorTest()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
NS_ASSERT_MSG(m_frerSeqRcvyLatentErrorPeriod >= m_frerSeqRcvyMinLatentErrorPeriod, "Trying to use a latent error test timer shorter than " << m_frerSeqRcvyMaxLatentErrorPeriod << ".");
|
||||
NS_ASSERT_MSG(m_frerSeqRcvyLatentErrorPeriod <= m_frerSeqRcvyMaxLatentErrorPeriod, "Trying to use a latent error test timer longer than " << m_frerSeqRcvyMaxLatentErrorPeriod << ".");
|
||||
NS_ASSERT_MSG(m_frerSeqRcvyLatentResetPeriod >= m_frerSeqRcvyMinLatentResetPeriod, "Trying to use a latent error reset timer shorter than " << m_frerSeqRcvyMinLatentResetPeriod << ".");
|
||||
NS_ASSERT_MSG(m_frerSeqRcvyLatentResetPeriod <= m_frerSeqRcvyMaxLatentResetPeriod, "Trying to use a latent error reset timer longer than " << m_frerSeqRcvyMaxLatentResetPeriod << ".");
|
||||
|
||||
// NS_LOG_INFO("Latent Error Test ! ");
|
||||
NS_ASSERT_MSG(m_recoveryFunction!=nullptr, "Recovery function not set ...");
|
||||
|
||||
int diff = m_curBaseDifference - ((m_recoveryFunction->GetFrerCpsSeqRcvyPassedPackets() *(m_frerSeqRcvyLatentErrorPaths - 1)) - m_recoveryFunction->GetFrerCpsSeqRcvyDiscardedPackets());
|
||||
if (m_frerSeqRcvyLatentErrorPaths > 1 )
|
||||
{
|
||||
if (diff < 0)
|
||||
{
|
||||
diff = - diff;
|
||||
}
|
||||
|
||||
if (diff > (int)m_frerSeqRcvyLatentErrorDifference)
|
||||
{
|
||||
NS_LOG_INFO("Latent Error Detected ! ");
|
||||
//Hit a trace ?
|
||||
}
|
||||
}
|
||||
|
||||
m_testEvent = Simulator::Schedule(m_frerSeqRcvyLatentErrorPeriod, &LatentErrorDetectionFunction::LatentErrorTest, this);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
71
contrib/tsn/model/frer-latent-error-detection-function.h
Normal file
71
contrib/tsn/model/frer-latent-error-detection-function.h
Normal file
@@ -0,0 +1,71 @@
|
||||
#ifndef FRER_LATENT_ERROR_DETECTION_FUNCTION_H
|
||||
#define FRER_LATENT_ERROR_DETECTION_FUNCTION_H
|
||||
|
||||
#include "ns3/object.h"
|
||||
|
||||
#include "ns3/nstime.h"
|
||||
|
||||
#include "frer-base-recovery-function.h"
|
||||
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
class LatentErrorDetectionFunction : public Object
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \brief Get the TypeId
|
||||
*
|
||||
* \return The TypeId for this class
|
||||
*/
|
||||
static TypeId GetTypeId();
|
||||
|
||||
/**
|
||||
* \brief Create a LatentErrorDetectionFunction
|
||||
*/
|
||||
LatentErrorDetectionFunction();
|
||||
|
||||
/**
|
||||
* Destroy a LatentErrorDetectionFunction
|
||||
*
|
||||
* This is the destructor for the LatentErrorDetectionFunction.
|
||||
*/
|
||||
~LatentErrorDetectionFunction();
|
||||
|
||||
// Delete copy constructor and assignment operator to avoid misuse
|
||||
LatentErrorDetectionFunction& operator=(const LatentErrorDetectionFunction&) = delete;
|
||||
LatentErrorDetectionFunction(const LatentErrorDetectionFunction&) = delete;
|
||||
|
||||
void SetRecoveryFunction(Ptr<BaseRecoveryFunction> recoveryFunction);
|
||||
void LatentErrorReset(); //802.1CB-2017 : 7.4.4.3
|
||||
void LatentErrorTest(); //802.1CB-2017 : 7.4.4.4
|
||||
|
||||
protected:
|
||||
Ptr<BaseRecoveryFunction> m_recoveryFunction = nullptr;
|
||||
|
||||
int m_curBaseDifference = 0; //802.1CB-2017 : 7.4.4.2.1
|
||||
|
||||
uint m_frerSeqRcvyLatentErrorDifference; //802.1CB-2017 : 10.4.1.12.1
|
||||
Time m_frerSeqRcvyLatentErrorPeriod; //802.1CB-2017 : 10.4.1.12.2
|
||||
Time m_frerSeqRcvyLatentResetPeriod; //802.1CB-2017 : 10.4.1.12.4
|
||||
|
||||
uint m_frerSeqRcvyLatentErrorPaths; //802.1CB-2017 : 10.4.1.12.3
|
||||
uint m_frerCpsSeqRcvyLatentErrorResets = 0; //802.1CB-2017 : 10.8.10
|
||||
|
||||
Time m_frerSeqRcvyMinLatentErrorPeriod;
|
||||
Time m_frerSeqRcvyMaxLatentErrorPeriod;
|
||||
Time m_frerSeqRcvyMinLatentResetPeriod;
|
||||
Time m_frerSeqRcvyMaxLatentResetPeriod;
|
||||
|
||||
EventId m_testEvent;
|
||||
EventId m_resetEvent;
|
||||
|
||||
|
||||
private:
|
||||
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
#endif /* FRER_LATENT_ERROR_DETECTION_FUNCTION_H */
|
||||
78
contrib/tsn/model/frer-match-recovery-function.cc
Normal file
78
contrib/tsn/model/frer-match-recovery-function.cc
Normal file
@@ -0,0 +1,78 @@
|
||||
#include "frer-match-recovery-function.h"
|
||||
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/simulator.h"
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("MatchRecoveryFunction");
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED(MatchRecoveryFunction);
|
||||
|
||||
TypeId
|
||||
MatchRecoveryFunction::GetTypeId()
|
||||
{
|
||||
static TypeId tid =
|
||||
TypeId("ns3::MatchRecoveryFunction")
|
||||
.SetParent<BaseRecoveryFunction>()
|
||||
.SetGroupName("tsn")
|
||||
.AddConstructor<MatchRecoveryFunction>();
|
||||
return tid;
|
||||
}
|
||||
|
||||
|
||||
MatchRecoveryFunction::MatchRecoveryFunction()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
}
|
||||
|
||||
MatchRecoveryFunction::~MatchRecoveryFunction()
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
}
|
||||
|
||||
bool
|
||||
MatchRecoveryFunction::DoRecovery(uint16_t seqNumber)
|
||||
{
|
||||
NS_LOG_FUNCTION(this);
|
||||
NS_ASSERT_MSG(m_frerSeqRcvyResetMSec <= m_frerMaxSeqRcvyResetMSec, "Trying to use a longer recovery reset timer than " << m_frerMaxSeqRcvyResetMSec << ".");
|
||||
if(m_takeAny)
|
||||
{
|
||||
m_takeAny = false;
|
||||
m_frerCpsSeqRcvyPassedPackets += 1;
|
||||
m_recovSeqNum = seqNumber;
|
||||
Simulator::Cancel(m_resetEvent);
|
||||
m_resetEvent = Simulator::Schedule(m_frerSeqRcvyResetMSec, &BaseRecoveryFunction::resetRecoveryFunction, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint16_t delta = (seqNumber - m_recovSeqNum)%m_recovSeqSpace;
|
||||
if (delta == 0)
|
||||
{
|
||||
//Pkt has been seen ... drop it
|
||||
m_frerCpsSeqRcvyDiscardedPackets += 1;
|
||||
if(m_frerSeqRcvyIndividualRecovery)
|
||||
{
|
||||
Simulator::Cancel(m_resetEvent);
|
||||
m_resetEvent = Simulator::Schedule(m_frerSeqRcvyResetMSec, &BaseRecoveryFunction::resetRecoveryFunction, this);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Pkt hasn't been seen ... accept it
|
||||
if (delta != 1)
|
||||
{
|
||||
//Pkt is out of order
|
||||
m_frerCpsSeqRcvyOutOfOrderPackets += 1;
|
||||
}
|
||||
m_frerCpsSeqRcvyPassedPackets += 1;
|
||||
m_recovSeqNum = seqNumber;
|
||||
Simulator::Cancel(m_resetEvent);
|
||||
m_resetEvent = Simulator::Schedule(m_frerSeqRcvyResetMSec, &BaseRecoveryFunction::resetRecoveryFunction, this);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
47
contrib/tsn/model/frer-match-recovery-function.h
Normal file
47
contrib/tsn/model/frer-match-recovery-function.h
Normal file
@@ -0,0 +1,47 @@
|
||||
#ifndef FRER_MATCH_RECOVERY_FUNCTION_H
|
||||
#define FRER_MATCH_RECOVERY_FUNCTION_H
|
||||
|
||||
#include "ns3/frer-base-recovery-function.h"
|
||||
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
class MatchRecoveryFunction : public BaseRecoveryFunction
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \brief Get the TypeId
|
||||
*
|
||||
* \return The TypeId for this class
|
||||
*/
|
||||
static TypeId GetTypeId();
|
||||
|
||||
/**
|
||||
* \brief Create a MatchRecoveryFunction
|
||||
*/
|
||||
MatchRecoveryFunction();
|
||||
|
||||
/**
|
||||
* Destroy a MatchRecoveryFunction
|
||||
*
|
||||
* This is the destructor for the MatchRecoveryFunction.
|
||||
*/
|
||||
~MatchRecoveryFunction();
|
||||
|
||||
// Delete copy constructor and assignment operator to avoid misuse
|
||||
MatchRecoveryFunction& operator=(const MatchRecoveryFunction&) = delete;
|
||||
MatchRecoveryFunction(const MatchRecoveryFunction&) = delete;
|
||||
|
||||
bool DoRecovery(uint16_t seqNumber) override;
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
private:
|
||||
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
#endif /* FRER_MATCH_RECOVERY_FUNCTION_H */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user