#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 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 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 n0 = CreateObject(); Names::Add("ES1", n0); Ptr n1 = CreateObject(); Names::Add("ES2", n1); Ptr n2 = CreateObject(); Names::Add("ES3", n2); Ptr n3 = CreateObject(); Names::Add("SW1", n3); //Create and add clock to TsnNode Ptr c0 = CreateObject(); c0->SetAttribute("InitialOffset", TimeValue(Seconds(112))); c0->SetAttribute("DriftRate", DoubleValue(-15)); c0->SetAttribute("Granularity", TimeValue(NanoSeconds(10))); n0->SetMainClock(c0); Ptr c1 = CreateObject(); c1->SetAttribute("InitialOffset", TimeValue(Seconds(3))); c1->SetAttribute("DriftRate", DoubleValue(10)); c1->SetAttribute("Granularity", TimeValue(NanoSeconds(10))); n1->SetMainClock(c1); Ptr c2 = CreateObject(); c2->SetAttribute("InitialOffset", TimeValue(Seconds(1.5))); c2->SetAttribute("DriftRate", DoubleValue(-8)); c2->SetAttribute("Granularity", TimeValue(NanoSeconds(10))); n2->SetMainClock(c2); Ptr c3 = CreateObject(); 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 net0 = CreateObject(); net0->SetAttribute("DataRate", DataRateValue(DataRate("1Gb/s"))); n0->AddDevice(net0); Names::Add("ES1#01", net0); Ptr net1 = CreateObject(); net1->SetAttribute("DataRate", DataRateValue(DataRate("1Gb/s"))); n1->AddDevice(net1); Names::Add("ES2#01", net1); Ptr net2 = CreateObject(); net2->SetAttribute("DataRate", DataRateValue(DataRate("1Gb/s"))); n2->AddDevice(net2); Names::Add("ES3#01", net2); Ptr net3_0 = CreateObject(); net3_0->SetAttribute("DataRate", DataRateValue(DataRate("1Gb/s"))); n3->AddDevice(net3_0); Names::Add("SW1#01", net3_0); Ptr net3_1 = CreateObject(); net3_1->SetAttribute("DataRate", DataRateValue(DataRate("1Gb/s"))); n3->AddDevice(net3_1); Names::Add("SW1#02", net3_1); Ptr net3_2 = CreateObject(); 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 sw = CreateObject(); 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 l0 = CreateObject(); l0->SetAttribute("Delay", TimeValue(Time(NanoSeconds(200)))); net0->Attach(l0); net3_0->Attach(l0); Ptr l1 = CreateObject(); l1->SetAttribute("Delay", TimeValue(Time(NanoSeconds(200)))); net1->Attach(l1); net3_1->Attach(l1); Ptr l2 = CreateObject(); 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>()); net1->SetQueue(CreateObject>()); net2->SetQueue(CreateObject>()); net3_0->SetQueue(CreateObject>()); net3_1->SetQueue(CreateObject>()); net3_2->SetQueue(CreateObject>()); //Add and configure GPTP Ptr gPTP0 = CreateObject(); 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 gPTP1 = CreateObject(); 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 gPTP2 = CreateObject(); 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 gPTP3 = CreateObject(); 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; }