Network customization
Introduction
In the previous chapter, we wrote a simulation script for a simple Ethernet network. In this chapter, we will discuss how to customize it using the attributes of the different classes used.
Attributes in ns-3
To organize access and configuration of instantiated object parameters, ns-3 uses its own attribute system.
In the previous chapter, we already implemented this overlay using the “SetAttribute()” function to configure the application. This function has two arguments. The first is a string corresponding to the name of the attribute to be changed. The second is the value to be assigned to this attribute.
The various attributes available for each object are visible in the C++ implementation of each object. Here is an example of the EthernetChannel object described in contrib/ethernet/model/ethernet-channel.cc.
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;
}
We can see that this object has only one attribute called Delay, which allows you to configure the propagation delay. It is of type Time and has a default value of 25ns.
Thus, it is possible to configure the propagation delay in the previous simulation script as follows:
[...]
//Create Ethernet Channels and connect switch to the end-stations
Ptr<EthernetChannel> channel0 = CreateObject<EthernetChannel>();
channel0->SetAttribute("Delay", TimeValue(NanoSeconds(50)));
net0->Attach(channel0);
swnet0->Attach(channel0);
Ptr<EthernetChannel> channel1 = CreateObject<EthernetChannel>();
channel1->SetAttribute("Delay", TimeValue(NanoSeconds(75)));
net1->Attach(channel1);
swnet1->Attach(channel1);
Ptr<EthernetChannel> channel2 = CreateObject<EthernetChannel>();
channel2->SetAttribute("Delay", TimeValue(NanoSeconds(100)));
net2->Attach(channel2);
swnet2->Attach(channel2);
[...]
Common attributes
Here are examples of the attributes most often used in Ethernet network simulations.
[...]
//Create and add a netDevice to each end-station 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);
Ptr<EthernetNetDevice> net2 = CreateObject<EthernetNetDevice>();
net2->SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
n2->AddDevice(net2);
Names::Add("ES3#01", net2);
//Create and add a netDevice to each switch port
Ptr<EthernetNetDevice> swnet0 = CreateObject<EthernetNetDevice>();
swnet0->SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
n3->AddDevice(swnet0);
Names::Add("SW#01", swnet0);
Ptr<EthernetNetDevice> swnet1 = CreateObject<EthernetNetDevice>();
swnet1->SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
n3->AddDevice(swnet1);
Names::Add("SW#02", swnet1);
Ptr<EthernetNetDevice> swnet2 = CreateObject<EthernetNetDevice>();
swnet2->SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
n3->AddDevice(swnet2);
Names::Add("SW#03", swnet2);
[...]
//Create Ethernet Channels and connect switch to the end-stations
Ptr<EthernetChannel> channel0 = CreateObject<EthernetChannel>();
channel0->SetAttribute("Delay", TimeValue(NanoSeconds(50)));
net0->Attach(channel0);
swnet0->Attach(channel0);
Ptr<EthernetChannel> channel1 = CreateObject<EthernetChannel>();
channel1->SetAttribute("Delay", TimeValue(NanoSeconds(75)));
net1->Attach(channel1);
swnet1->Attach(channel1);
Ptr<EthernetChannel> channel2 = CreateObject<EthernetChannel>();
channel2->SetAttribute("Delay", TimeValue(NanoSeconds(100)));
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(2)));
sw->SetAttribute("MaxForwardingLatency", TimeValue(MicroSeconds(5)));
n3->AddDevice(sw);
[...]
//Create 2 output port FIFOs for each netDevice.
for (int i=0; i<2; i++){
Ptr<DropTailQueue<Packet>> q0 = CreateObject<DropTailQueue<Packet>>();
q0->SetAttribute("MaxSize", QueueSizeValue(QueueSize("250p")));
net0->SetQueue(q0);
[...]
//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("InterFrame", TimeValue(MilliSeconds(20)));
app0->SetAttribute("Jitter", TimeValue(MilliSeconds(50)));
app0->SetAttribute("Offset", TimeValue(Seconds(1)));
app0->SetAttribute("VlanID", UintegerValue(1));
app0->SetAttribute("PCP", UintegerValue(1));
app0->SetAttribute("DEI", UintegerValue(0));
[...]
Final simulation script
Here is the simulation script you should have at the end of this chapter.
#include "ns3/simulator.h"
#include "ns3/core-module.h"
#include "ns3/node.h"
#include "ns3/drop-tail-queue.h"
#include "ns3/ethernet-net-device.h"
#include "ns3/ethernet-channel.h"
#include "ns3/switch-net-device.h"
#include "ns3/ethernet-generator.h"
using namespace ns3;
NS_LOG_COMPONENT_DEFINE("Chapter 2");
//A callback to log the pkt emission
static void
MacTxCallback(std::string context, Ptr<const Packet> p)
{
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " sent!");
}
//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("Chapter 2", LOG_LEVEL_INFO);
//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>();
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);
Ptr<EthernetNetDevice> net2 = CreateObject<EthernetNetDevice>();
net2->SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
n2->AddDevice(net2);
Names::Add("ES3#01", net2);
//Create and add a netDevice to each switch port
Ptr<EthernetNetDevice> swnet0 = CreateObject<EthernetNetDevice>();
swnet0->SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
n3->AddDevice(swnet0);
Names::Add("SW#01", swnet0);
Ptr<EthernetNetDevice> swnet1 = CreateObject<EthernetNetDevice>();
swnet1->SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
n3->AddDevice(swnet1);
Names::Add("SW#02", swnet1);
Ptr<EthernetNetDevice> swnet2 = CreateObject<EthernetNetDevice>();
swnet2->SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
n3->AddDevice(swnet2);
Names::Add("SW#03", swnet2);
//Create Ethernet Channels and connect switch to the end-stations
Ptr<EthernetChannel> channel0 = CreateObject<EthernetChannel>();
channel0->SetAttribute("Delay", TimeValue(NanoSeconds(50)));
net0->Attach(channel0);
swnet0->Attach(channel0);
Ptr<EthernetChannel> channel1 = CreateObject<EthernetChannel>();
channel1->SetAttribute("Delay", TimeValue(NanoSeconds(75)));
net1->Attach(channel1);
swnet1->Attach(channel1);
Ptr<EthernetChannel> channel2 = CreateObject<EthernetChannel>();
channel2->SetAttribute("Delay", TimeValue(NanoSeconds(100)));
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(2)));
sw->SetAttribute("MaxForwardingLatency", TimeValue(MicroSeconds(5)));
n3->AddDevice(sw);
sw->AddSwitchPort(swnet0);
sw->AddSwitchPort(swnet1);
sw->AddSwitchPort(swnet2);
//Allocate Mac addresses to the netDevices
net0->SetAddress(Mac48Address::Allocate());
net1->SetAddress(Mac48Address::Allocate());
net2->SetAddress(Mac48Address::Allocate());
sw->SetAddress(Mac48Address::Allocate());
//Create 2 output port FIFOs for each netDevice.
for (int i=0; i<2; i++){
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
net2->SetQueue(CreateObject<DropTailQueue<Packet>>());
swnet0->SetQueue(CreateObject<DropTailQueue<Packet>>());
swnet1->SetQueue(CreateObject<DropTailQueue<Packet>>());
swnet2->SetQueue(CreateObject<DropTailQueue<Packet>>());
}
//Add a forwarding table entry
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("InterFrame", TimeValue(MilliSeconds(20)));
app0->SetAttribute("Jitter", TimeValue(MilliSeconds(50)));
app0->SetAttribute("Offset", TimeValue(Seconds(1)));
app0->SetAttribute("VlanID", UintegerValue(1));
app0->SetAttribute("PCP", UintegerValue(1));
app0->SetAttribute("DEI", UintegerValue(0));
n0->AddApplication(app0);
app0->SetStartTime(Seconds(0));
app0->SetStopTime(Seconds(10));
//Callback declarations
//Callback to display the packet sent log
std::string context = Names::FindName(n0) + ":" + Names::FindName(net0);
net0->TraceConnectWithoutContext("MacTx", MakeBoundCallback(&MacTxCallback, context));
//Callback to display the packet received log
context = Names::FindName(n2) + ":" + Names::FindName(net2);
net2->TraceConnectWithoutContext("MacRx", MakeBoundCallback(&MacRxCallback, context));
//Execute the simulation
NS_LOG_INFO("Start of the simulation");
Simulator::Stop(Seconds(10));
Simulator::Run();
Simulator::Destroy();
NS_LOG_INFO("End of the simulation");
return 0;
}