To implement a custom Data link layer (DLL) in ns3, this makes new classes that execute the characteristics of DLL that contains framing, error classification and medium access control. Here are the steps on how to implement the custom data link layer in ns3:
Steps to Implement a Custom Data Link Layer in ns3
- Set Up Your ns3 Workspace: Make certain ns3 is installed in the computer and configure with working directory.
- Create a New Module for the Data Link Layer:
- Navigate to the src directory of ns3 and create a new directory named custom-dll.
- Inside the custom-dll directory, create subdirectories: model, helper, and examples.
- Define the Data Link Layer Classes:
- In the model directory, create .cc and .h files for the data link layer. Define the classes that simulate the behavior of the data link layer, such as CustomMac, CustomChannel, and CustomNetDevice.
- Implement the Data Link Layer Classes:
- The key components of data link layer are framing, classifying the error, and the medium access control.
- Generate classes for the data link channel and network device that communicate with the data link layer.
- Integrate the Data Link Layer with ns3 Network System:
- Modify the NetDevice class or create a custom network device that can handle the data link layer logic.
- Register the custom data link layer as a protocol in ns3.
- Create a Simulation Script:
- Set up a network topology.
- Download the Internet stack.
- Use the custom data link layer helper to enable the data link layer.
- Configure applications and execute the simulation.
Example Code Structure
The given below is the sample snippet to implement the custom data link layer in ns3:
- Define Custom Data Link Layer Classes
// src/custom-dll/model/custom-mac.h
#ifndef CUSTOM_MAC_H
#define CUSTOM_MAC_H
#include “ns3/object.h”
#include “ns3/net-device.h”
#include “ns3/packet.h”
#include “ns3/nstime.h”
namespace ns3 {
class CustomChannel;
class CustomMac : public Object
{
public:
static TypeId GetTypeId (void);
CustomMac ();
virtual ~CustomMac ();
void SetChannel (Ptr<CustomChannel> channel);
void SendPacket (Ptr<Packet> packet);
void ReceivePacket (Ptr<Packet> packet);
private:
void TransmitPacket ();
Ptr<CustomChannel> m_channel;
Ptr<Packet> m_txPacket;
Time m_txDuration;
};
} // namespace ns3
#endif // CUSTOM_MAC_H
2. Implement Custom Data Link Layer Classes
// src/custom-dll/model/custom-mac.cc
#include “custom-mac.h”
#include “custom-channel.h”
#include “ns3/log.h”
#include “ns3/simulator.h”
namespace ns3 {
NS_LOG_COMPONENT_DEFINE (“CustomMac”);
NS_OBJECT_ENSURE_REGISTERED (CustomMac);
TypeId
CustomMac::GetTypeId (void)
{
static TypeId tid = TypeId (“ns3::CustomMac”)
.SetParent<Object> ()
.SetGroupName (“Network”)
.AddConstructor<CustomMac> ();
return tid;
}
CustomMac::CustomMac ()
{
NS_LOG_FUNCTION (this);
}
CustomMac::~CustomMac ()
{
NS_LOG_FUNCTION (this);
}
void
CustomMac::SetChannel (Ptr<CustomChannel> channel)
{
NS_LOG_FUNCTION (this << channel);
m_channel = channel;
}
void
CustomMac::SendPacket (Ptr<Packet> packet)
{
NS_LOG_FUNCTION (this << packet);
m_txPacket = packet;
m_txDuration = Seconds (packet->GetSize () * 8 / 1e6); // Example: 1 Mbps data rate
Simulator::Schedule (m_txDuration, &CustomMac::TransmitPacket, this);
}
void
CustomMac::TransmitPacket ()
{
NS_LOG_FUNCTION (this);
if (m_channel)
{
m_channel->Transmit (m_txPacket, this);
}
}
void
CustomMac::ReceivePacket (Ptr<Packet> packet)
{
NS_LOG_FUNCTION (this << packet);
// Process received packet (e.g., framing, error detection)
}
} // namespace ns3
3. Define Custom Channel
// src/custom-dll/model/custom-channel.h
#ifndef CUSTOM_CHANNEL_H
#define CUSTOM_CHANNEL_H
#include “ns3/object.h”
#include “ns3/nstime.h”
#include “ns3/traced-callback.h”
#include “ns3/net-device.h”
#include “ns3/custom-mac.h”
namespace ns3 {
class CustomChannel : public Object
{
public:
static TypeId GetTypeId (void);
CustomChannel ();
virtual ~CustomChannel ();
void AddDevice (Ptr<NetDevice> device, Ptr<CustomMac> mac);
void Transmit (Ptr<Packet> packet, Ptr<CustomMac> sender);
private:
struct DeviceEntry
{
Ptr<NetDevice> device;
Ptr<CustomMac> mac;
};
std::vector<DeviceEntry> m_devices;
};
} // namespace ns3
#endif // CUSTOM_CHANNEL_H
4. Implement Custom Channel
// src/custom-dll/model/custom-channel.cc
#include “custom-channel.h”
#include “ns3/log.h”
#include “ns3/simulator.h”
namespace ns3 {
NS_LOG_COMPONENT_DEFINE (“CustomChannel”);
NS_OBJECT_ENSURE_REGISTERED (CustomChannel);
TypeId
CustomChannel::GetTypeId (void)
{
static TypeId tid = TypeId (“ns3::CustomChannel”)
.SetParent<Object> ()
.SetGroupName (“Network”)
.AddConstructor<CustomChannel> ();
return tid;
}
CustomChannel::CustomChannel ()
{
NS_LOG_FUNCTION (this);
}
CustomChannel::~CustomChannel ()
{
NS_LOG_FUNCTION (this);
}
void
CustomChannel::AddDevice (Ptr<NetDevice> device, Ptr<CustomMac> mac)
{
NS_LOG_FUNCTION (this << device << mac);
DeviceEntry entry = {device, mac};
m_devices.push_back (entry);
}
void
CustomChannel::Transmit (Ptr<Packet> packet, Ptr<CustomMac> sender)
{
NS_LOG_FUNCTION (this << packet << sender);
// Simulate propagation delay and attenuation
Time delay = MilliSeconds (1); // Example: fixed delay
for (auto &entry : m_devices)
{
if (entry.mac != sender)
{
Simulator::ScheduleWithContext (entry.device->GetNode ()->GetId (),
delay, &CustomMac::ReceivePacket,
entry.mac, packet->Copy ());
}
}
}
} // namespace ns3
Define Custom Net Device
// src/custom-dll/model/custom-net-device.h
#ifndef CUSTOM_NET_DEVICE_H
#define CUSTOM_NET_DEVICE_H
#include “ns3/net-device.h”
#include “ns3/node.h”
#include “ns3/mac48-address.h”
#include “ns3/packet.h”
#include “custom-mac.h”
namespace ns3 {
class CustomNetDevice : public NetDevice
{
public:
static TypeId GetTypeId (void);
CustomNetDevice ();
virtual ~CustomNetDevice ();
void SetMac (Ptr<CustomMac> mac);
// Inherited from NetDevice
virtual void SetIfIndex (const uint32_t index);
virtual uint32_t GetIfIndex (void) const;
virtual Ptr<Channel> GetChannel (void) const;
virtual void SetAddress (Address address);
virtual Address GetAddress (void) const;
virtual bool SetMtu (const uint16_t mtu);
virtual uint16_t GetMtu (void) const;
virtual bool IsLinkUp (void) const;
virtual void AddLinkChangeCallback (Callback<void> callback);
virtual bool IsBroadcast (void) const;
virtual Address GetBroadcast (void) const;
virtual bool IsMulticast (void) const;
virtual Address GetMulticast (Ipv4Address multicastGroup) const;
virtual bool IsPointToPoint (void) const;
virtual bool IsBridge (void) const;
virtual bool Send (Ptr<Packet> packet, const Address &dest, uint16_t protocolNumber);
virtual bool SendFrom (Ptr<Packet> packet, const Address &source, const Address &dest, uint16_t protocolNumber);
virtual Ptr<Node> GetNode (void) const;
virtual void SetNode (Ptr<Node> node);
virtual bool NeedsArp (void) const;
virtual void SetReceiveCallback (NetDevice::ReceiveCallback cb);
virtual void SetPromiscReceiveCallback (PromiscReceiveCallback cb);
virtual bool SupportsSendFrom (void) const;
private:
Ptr<CustomMac> m_mac;
Ptr<Node> m_node;
Mac48Address m_address;
NetDevice::ReceiveCallback m_rxCallback;
};
} // namespace ns3
#endif // CUSTOM_NET_DEVICE_H
5. Implement Custom Net Device
// src/custom-dll/model/custom-net-device.cc
#include “custom-net-device.h”
#include “ns3/log.h”
#include “ns3/packet.h”
#include “ns3/simulator.h”
#include “ns3/node.h”
namespace ns3 {
NS_LOG_COMPONENT_DEFINE (“CustomNetDevice”);
NS_OBJECT_ENSURE_REGISTERED (CustomNetDevice);
TypeId
CustomNetDevice::GetTypeId (void)
{
static TypeId tid = TypeId (“ns3::CustomNetDevice”)
.SetParent<NetDevice> ()
.SetGroupName (“Network”)
.AddConstructor<CustomNetDevice> ();
return tid;
}
CustomNetDevice::CustomNetDevice ()
{
NS_LOG_FUNCTION (this);
}
CustomNetDevice::~CustomNetDevice ()
{
NS_LOG_FUNCTION (this);
}
void
CustomNetDevice::SetMac (Ptr<CustomMac> mac)
{
NS_LOG_FUNCTION (this << mac);
m_mac = mac;
}
void
CustomNetDevice::SetIfIndex (const uint32_t index)
{
NS_LOG_FUNCTION (this << index);
}
uint32_t
CustomNetDevice::GetIfIndex (void) const
{
NS_LOG_FUNCTION (this);
return 0;
}
Ptr<Channel>
CustomNetDevice::GetChannel (void) const
{
NS_LOG_FUNCTION (this);
return m_mac->GetObject<Channel> ();
}
void
CustomNetDevice::SetAddress (Address address)
{
NS_LOG_FUNCTION (this << address);
m_address = Mac48Address::ConvertFrom (address);
}
Address
CustomNetDevice::GetAddress (void) const
{
NS_LOG_FUNCTION (this);
return m_address;
}
bool
CustomNetDevice::SetMtu (const uint16_t mtu)
{
NS_LOG_FUNCTION (this << mtu);
return true;
}
uint16_t
CustomNetDevice::GetMtu (void) const
{
NS_LOG_FUNCTION (this);
return 1500;
}
bool
CustomNetDevice::IsLinkUp (void) const
{
NS_LOG_FUNCTION (this);
return true;
}
void
CustomNetDevice::AddLinkChangeCallback (Callback<void> callback)
{
NS_LOG_FUNCTION (this << &callback);
}
bool
CustomNetDevice::IsBroadcast (void) const
{
NS_LOG_FUNCTION (this);
return true;
}
Address
CustomNetDevice::GetBroadcast (void) const
{
NS_LOG_FUNCTION (this);
return Mac48Address::GetBroadcast ();
}
bool
CustomNetDevice::IsMulticast (void) const
{
NS_LOG_FUNCTION (this);
return true;
}
Address
CustomNetDevice::GetMulticast (Ipv4Address multicastGroup) const
{
NS_LOG_FUNCTION (this << multicastGroup);
return Mac48Address::GetMulticast (multicastGroup);
}
bool
CustomNetDevice::IsPointToPoint (void) const
{
NS_LOG_FUNCTION (this);
return false;
}
bool
CustomNetDevice::IsBridge (void) const
{
NS_LOG_FUNCTION (this);
return false;
}
bool
CustomNetDevice::Send (Ptr<Packet> packet, const Address &dest, uint16_t protocolNumber)
{
NS_LOG_FUNCTION (this << packet << dest << protocolNumber);
m_mac->SendPacket (packet);
return true;
}
bool
CustomNetDevice::SendFrom (Ptr<Packet> packet, const Address &source, const Address &dest, uint16_t protocolNumber)
{
NS_LOG_FUNCTION (this << packet << source << dest << protocolNumber);
return Send (packet, dest, protocolNumber);
}
Ptr<Node>
CustomNetDevice::GetNode (void) const
{
NS_LOG_FUNCTION (this);
return m_node;
}
void
CustomNetDevice::SetNode (Ptr<Node> node)
{
NS_LOG_FUNCTION (this << node);
m_node = node;
}
bool
CustomNetDevice::NeedsArp (void) const
{
NS_LOG_FUNCTION (this);
return true;
}
void
CustomNetDevice::SetReceiveCallback (NetDevice::ReceiveCallback cb)
{
NS_LOG_FUNCTION (this << &cb);
m_rxCallback = cb;
}
void
CustomNetDevice::SetPromiscReceiveCallback (PromiscReceiveCallback cb)
{
NS_LOG_FUNCTION (this << &cb);
}
bool
CustomNetDevice::SupportsSendFrom (void) const
{
NS_LOG_FUNCTION (this);
return true;
}
} // namespace ns3
6. Define Custom Helper
// src/custom-dll/helper/custom-dll-helper.h
#ifndef CUSTOM_DLL_HELPER_H
#define CUSTOM_DLL_HELPER_H
#include “ns3/net-device-container.h”
#include “ns3/object-factory.h”
#include “ns3/custom-mac.h”
#include “ns3/custom-net-device.h”
#include “ns3/custom-channel.h”
namespace ns3 {
class CustomDllHelper
{
public:
CustomDllHelper ();
void Install (NodeContainer c) const;
void Install (Ptr<Node> node) const;
void Install (Ptr<NetDevice> device) const;
private:
ObjectFactory m_macFactory;
ObjectFactory m_deviceFactory;
ObjectFactory m_channelFactory;
};
} // namespace ns3
#endif // CUSTOM_DLL_HELPER_H
7. Implement Custom Helper
// src/custom-dll/helper/custom-dll-helper.cc
#include “custom-dll-helper.h”
#include “ns3/custom-mac.h”
#include “ns3/custom-net-device.h”
#include “ns3/custom-channel.h”
#include “ns3/node.h”
#include “ns3/ipv4.h”
namespace ns3 {
CustomDllHelper::CustomDllHelper ()
{
m_macFactory.SetTypeId (CustomMac::GetTypeId ());
m_deviceFactory.SetTypeId (CustomNetDevice::GetTypeId ());
m_channelFactory.SetTypeId (CustomChannel::GetTypeId ());
}
void
CustomDllHelper::Install (NodeContainer c) const
{
for (NodeContainer::Iterator i = c.Begin (); i != c.End (); ++i)
{
Install (*i);
}
}
void
CustomDllHelper::Install (Ptr<Node> node) const
{
Ptr<CustomChannel> channel = m_channelFactory.Create<CustomChannel> ();
for (uint32_t i = 0; i < node->GetNDevices (); ++i)
{
Ptr<NetDevice> device = node->GetDevice (i);
Install (device);
Ptr<CustomNetDevice> customDevice = device->GetObject<CustomNetDevice> ();
customDevice->SetChannel (channel);
channel->AddDevice (device, customDevice->GetObject<CustomMac> ());
}
}
void
CustomDllHelper::Install (Ptr<NetDevice> device) const
{
Ptr<CustomMac> mac = m_macFactory.Create<CustomMac> ();
Ptr<CustomNetDevice> customDevice = m_deviceFactory.Create<CustomNetDevice> ();
customDevice->SetMac (mac);
device->GetNode ()->AddDevice (customDevice);
mac->SetChannel (device->GetObject<CustomChannel> ());
}
} // namespace ns3
Example Simulation Script
At this direction, we provide the sample script to complete the simulation via ns3:
// examples/custom-dll-simulation.cc
#include “ns3/core-module.h”
#include “ns3/network-module.h”
#include “ns3/internet-module.h”
#include “ns3/point-to-point-module.h”
#include “ns3/applications-module.h”
#include “ns3/custom-dll-helper.h”
using namespace ns3;
NS_LOG_COMPONENT_DEFINE (“CustomDllSimulation”);
int main (int argc, char *argv[])
{
CommandLine cmd;
cmd.Parse (argc, argv);
// Create nodes
NodeContainer nodes;
nodes.Create (4);
// Create point-to-point links
PointToPointHelper p2p;
p2p.SetDeviceAttribute (“DataRate”, StringValue (“1Gbps”));
p2p.SetChannelAttribute (“Delay”, StringValue (“2ms”));
NetDeviceContainer devices01 = p2p.Install (nodes.Get (0), nodes.Get (1));
NetDeviceContainer devices12 = p2p.Install (nodes.Get (1), nodes.Get (2));
NetDeviceContainer devices23 = p2p.Install (nodes.Get (2), nodes.Get (3));
NetDeviceContainer devices30 = p2p.Install (nodes.Get (3), nodes.Get (0));
// Install Custom DLL on all nodes
CustomDllHelper customDll;
customDll.Install (nodes);
// Install Internet stack
InternetStackHelper internet;
internet.Install (nodes);
// Assign IP addresses
Ipv4AddressHelper address;
address.SetBase (“10.1.1.0”, “255.255.255.0”);
Ipv4InterfaceContainer interfaces01 = address.Assign (devices01);
address.SetBase (“10.1.2.0”, “255.255.255.0”);
Ipv4InterfaceContainer interfaces12 = address.Assign (devices12);
address.SetBase (“10.1.3.0”, “255.255.255.0”);
Ipv4InterfaceContainer interfaces23 = address.Assign (devices23);
address.SetBase (“10.1.4.0”, “255.255.255.0”);
Ipv4InterfaceContainer interfaces30 = address.Assign (devices30);
// Create a packet sink to receive packets
uint16_t sinkPort = 8080;
Address sinkAddress (InetSocketAddress (Ipv4Address (“10.1.1.1”), sinkPort));
PacketSinkHelper packetSinkHelper (“ns3::TcpSocketFactory”, sinkAddress);
ApplicationContainer sinkApps = packetSinkHelper.Install (nodes.Get (0));
sinkApps.Start (Seconds (1.0));
sinkApps.Stop (Seconds (10.0));
// Create a TCP client to send packets
OnOffHelper clientHelper (“ns3::TcpSocketFactory”, sinkAddress); clientHelper.SetAttribute(“OnTime”,StringValue(“ns3::ConstantRandomVariable[Constant=1]”));
clientHelper.SetAttribute(“OffTime”,StringValue(“ns3::ConstantRandomVariable[Constant=0]”));
clientHelper.SetAttribute (“DataRate”, DataRateValue (DataRate (“1Mbps”)));
clientHelper.SetAttribute (“PacketSize”, UintegerValue (1024));
ApplicationContainer clientApps = clientHelper.Install (nodes.Get (1));
clientApps.Start (Seconds (2.0));
Overall, we had implemented the Data link layer that makes new classes and executed by its DLL characteristic in ns3 tool. We also offer and support further performance analysis on data link layer supports in different tools.