Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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