#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 p) { Ptr 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 p) { TimestampTag tag; if (!p->FindFirstMatchingByteTag(tag)) { return; } Time arrival = Simulator::Now(); Time latency = arrival - tag.GetTimestamp(); Ptr 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 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("ES4", n3); Ptr n4 = CreateObject(); Names::Add("SW", n4); //Create and add a netDevice to each node Ptr net0 = CreateObject(); n0->AddDevice(net0); Names::Add("ES1#01", net0); Ptr swnet0 = CreateObject(); n4->AddDevice(swnet0); Names::Add("SW#01", swnet0); Ptr swnet1 = CreateObject(); swnet1->SetAttribute("PLCALocalNodeId", UintegerValue(0)); swnet1->SetAttribute("PLCANodeCount", UintegerValue(4)); n4->AddDevice(swnet1); Names::Add("SW#02", swnet1); Ptr net1 = CreateObject(); net1->SetAttribute("PLCALocalNodeId", UintegerValue(1)); net1->SetAttribute("PLCANodeCount", UintegerValue(4)); n1->AddDevice(net1); Names::Add("ES2#01", net1); Ptr net2 = CreateObject(); net2->SetAttribute("PLCALocalNodeId", UintegerValue(2)); net2->SetAttribute("PLCANodeCount", UintegerValue(4)); n2->AddDevice(net2); Names::Add("ES3#01", net2); Ptr net3 = CreateObject(); net3->SetAttribute("PLCALocalNodeId", UintegerValue(3)); net3->SetAttribute("PLCANodeCount", UintegerValue(4)); n3->AddDevice(net3); Names::Add("ES4#01", net3); //Create a full-duplex channel Ptr channel0 = CreateObject(); net0->Attach(channel0); swnet0->Attach(channel0); //Create a 10Base-T1S Channel and attach it two the netDevices Ptr channel1 = CreateObject(); swnet1->Attach(channel1); net1->Attach(channel1); net2->Attach(channel1); net3->Attach(channel1); //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))); 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>()); net0->SetQueue(CreateObject>()); net1->SetAddress(Mac48Address::Allocate()); net1->SetQueue(CreateObject>()); net1->SetQueue(CreateObject>()); net2->SetAddress(Mac48Address::Allocate()); net2->SetQueue(CreateObject>()); net2->SetQueue(CreateObject>()); net3->SetAddress(Mac48Address::Allocate()); net3->SetQueue(CreateObject>()); net3->SetQueue(CreateObject>()); swnet0->SetAddress(Mac48Address::Allocate()); swnet0->SetQueue(CreateObject>()); swnet0->SetQueue(CreateObject>()); swnet1->SetAddress(Mac48Address::Allocate()); swnet1->SetQueue(CreateObject>()); swnet1->SetQueue(CreateObject>()); //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 app0 = CreateObject(); 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 app1 = CreateObject(); 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; }