A Discrete-Event Network Simulator
API
fd-emu-tc.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017 Universita' degli Studi di Napoli Federico II
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation;
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16  *
17  * Author: Pasquale Imputato <p.imputato@gmail.com>
18  */
19 
20 /*
21  * node
22  * --------------------------------------------------
23  * | |
24  * | pfifo_fast queueDiscType [pfifo_fast]|
25  * | bql [false] |
26  * | interface 0 interface 1 |
27  * | | | |
28  * --------------------------------------------------
29  * | |
30  * 1 Gbps access incoming link | | 100 Mbps bottleneck outgoing link
31  * ----------------------------------- -----------------------------------
32  *
33  * This example builds a node with two interfaces in emulation mode in
34  * either {raw, netmap}. The aim is to explore different qdiscs behaviours
35  * on the backlog of a device emulated bottleneck side.
36  *
37  * If you run emulation in netmap mode, you need before to load the
38  * netmap.ko module. The user is responsible for configuring and building
39  * netmap separately.
40  */
41 
42 #include "ns3/abort.h"
43 #include "ns3/core-module.h"
44 #include "ns3/fd-net-device-module.h"
45 #include "ns3/internet-apps-module.h"
46 #include "ns3/internet-module.h"
47 #include "ns3/ipv4-list-routing-helper.h"
48 #include "ns3/network-module.h"
49 #include "ns3/traffic-control-module.h"
50 
51 using namespace ns3;
52 
53 NS_LOG_COMPONENT_DEFINE("TrafficControlEmu");
54 
55 void
57 {
58  Simulator::Schedule(Seconds(0.001), &TcPacketsInQueue, q, stream);
59  *stream->GetStream() << Simulator::Now().GetSeconds() << " backlog " << q->GetNPackets() << "p "
60  << q->GetNBytes() << "b "
61  << " dropped " << q->GetStats().nTotalDroppedPackets << "p "
62  << q->GetStats().nTotalDroppedBytes << "b " << std::endl;
63 }
64 
65 #ifdef HAVE_NETMAP_USER_H
66 void
68 {
69  Simulator::Schedule(Seconds(0.001), &Inflight, dev, stream);
70  *stream->GetStream() << dev->GetBytesInNetmapTxRing() << std::endl;
71 }
72 #endif
73 
74 int
75 main(int argc, char* argv[])
76 {
77  NS_LOG_INFO("Traffic Control Emulation Example");
78 
79  std::string deviceName0("enx503f56005a2a");
80  std::string deviceName1("eno1");
81  std::string ip0("10.0.1.2");
82  std::string ip1("10.0.2.1");
83  std::string mask0("255.255.255.0");
84  std::string mask1("255.255.255.0");
85  std::string m0("00:00:00:aa:00:01");
86  std::string m1("00:00:00:aa:00:02");
87  std::string queueDiscType = "PfifoFast";
88  bool bql = false;
89 
90  uint32_t index = 0;
91  bool writer = true;
92 #ifdef HAVE_PACKET_H
93  std::string emuMode("raw");
94 #else // HAVE_NETMAP_USER_H is true (otherwise this example is not compiled)
95  std::string emuMode("netmap");
96 #endif
97 
99  cmd.AddValue("deviceName0", "Device name", deviceName0);
100  cmd.AddValue("deviceName1", "Device name", deviceName1);
101  cmd.AddValue("ip0", "Local IP address", ip0);
102  cmd.AddValue("ip1", "Local IP address", ip1);
103  cmd.AddValue("mask0", "Local mask", mask0);
104  cmd.AddValue("mask1", "Local mask", mask1);
105  cmd.AddValue("m0", "Mac address", m0);
106  cmd.AddValue("m1", "Mac address", m1);
107  cmd.AddValue("writer", "Enable write stats", writer);
108  cmd.AddValue("queueDiscType",
109  "Bottleneck queue disc type in {PfifoFast, ARED, CoDel, FqCoDel, PIE}",
110  queueDiscType);
111  cmd.AddValue("bql", "Enable byte queue limits on bottleneck netdevice", bql);
112  cmd.AddValue("index", "Experiment index", index);
113  cmd.AddValue("emuMode", "Emulation mode in {raw, netmap}", emuMode);
114  cmd.Parse(argc, argv);
115 
116  Ipv4Address localIp0(ip0.c_str());
117  Ipv4Address localIp1(ip1.c_str());
118  Ipv4Mask netmask0(mask0.c_str());
119  Ipv4Mask netmask1(mask1.c_str());
120  Mac48AddressValue mac0(m0.c_str());
121  Mac48AddressValue mac1(m1.c_str());
122 
123  //
124  // Since we are using a real piece of hardware we need to use the realtime
125  // simulator.
126  //
127  GlobalValue::Bind("SimulatorImplementationType", StringValue("ns3::RealtimeSimulatorImpl"));
128 
129  //
130  // Since we are going to be talking to real-world machines, we need to enable
131  // calculation of checksums in our protocols.
132  //
133  GlobalValue::Bind("ChecksumEnabled", BooleanValue(true));
134 
135  //
136  // In such a simple topology, the use of the helper API can be a hindrance
137  // so we drop down into the low level API and do it manually.
138  //
139  // First we need a single node.
140  //
141  NS_LOG_INFO("Create Node");
142  Ptr<Node> node = CreateObject<Node>();
143 
144  //
145  // Create an emu device, allocate a MAC address and point the device to the
146  // Linux device name. The device needs a transmit queueing discipline so
147  // create a droptail queue and give it to the device. Finally, "install"
148  // the device into the node.
149  //
150  // Do understand that the ns-3 allocated MAC address will be sent out over
151  // your network since the emu net device will spoof it. By default, this
152  // address will have an Organizationally Unique Identifier (OUI) of zero.
153  // The Internet Assigned Number Authority IANA
154  //
155  // https://www.iana.org/assignments/ieee-802-numbers/ieee-802-numbers.txt
156  //
157  // reports that this OUI is unassigned, and so should not conflict with
158  // real hardware on your net. It may raise all kinds of red flags in a
159  // real environment to have packets from a device with an obviously bogus
160  // OUI flying around. Be aware.
161  //
162 
163  NS_LOG_INFO("Create Devices");
164 
165  FdNetDeviceHelper* helper0 = nullptr;
166  FdNetDeviceHelper* helper1 = nullptr;
167 
168 #ifdef HAVE_PACKET_H
169  if (emuMode == "raw")
170  {
171  auto raw0 = new EmuFdNetDeviceHelper;
172  raw0->SetDeviceName(deviceName0);
173  helper0 = raw0;
174 
175  auto raw1 = new EmuFdNetDeviceHelper;
176  raw1->SetDeviceName(deviceName1);
177  helper1 = raw1;
178  }
179 #endif
180 #ifdef HAVE_NETMAP_USER_H
181  if (emuMode == "netmap")
182  {
184  netmap0->SetDeviceName(deviceName0);
185  helper0 = netmap0;
186 
188  netmap1->SetDeviceName(deviceName1);
189  helper1 = netmap1;
190  }
191 #endif
192 
193  if ((helper0 == nullptr) || (helper1 == nullptr))
194  {
195  NS_ABORT_MSG(emuMode << " not supported.");
196  }
197 
198  NetDeviceContainer devices0 = helper0->Install(node);
199  NetDeviceContainer devices1 = helper1->Install(node);
200 
201  Ptr<NetDevice> device0 = devices0.Get(0);
202  device0->SetAttribute("Address", mac0);
203 
204  Ptr<NetDevice> device1 = devices1.Get(0);
205  device1->SetAttribute("Address", mac1);
206 
207  //
208  // Add a default internet stack to the node. This gets us the ns-3 versions
209  // of ARP, IPv4, ICMP, UDP and TCP.
210  //
211  NS_LOG_INFO("Add Internet Stack");
212  InternetStackHelper internetStackHelper;
213  internetStackHelper.Install(node);
214 
215  Ptr<Ipv4> ipv4 = node->GetObject<Ipv4>();
216 
217  NS_LOG_INFO("Create IPv4 Interface 0");
218  uint32_t interface0 = ipv4->AddInterface(device0);
219  Ipv4InterfaceAddress address0 = Ipv4InterfaceAddress(localIp0, netmask0);
220  ipv4->AddAddress(interface0, address0);
221  ipv4->SetMetric(interface0, 0);
222  ipv4->SetForwarding(interface0, true);
223  ipv4->SetUp(interface0);
224 
225  NS_LOG_INFO("Create IPv4 Interface 1");
226  uint32_t interface1 = ipv4->AddInterface(device1);
227  Ipv4InterfaceAddress address1 = Ipv4InterfaceAddress(localIp1, netmask1);
228  ipv4->AddAddress(interface1, address1);
229  ipv4->SetMetric(interface1, 0);
230  ipv4->SetForwarding(interface1, true);
231  ipv4->SetUp(interface1);
232 
234 
235  // Traffic control configurations
236  // Access link side
238  tch0.SetRootQueueDisc("ns3::PfifoFastQueueDisc", "MaxSize", StringValue("1000p"));
239  tch0.Install(devices0);
240 
241  // Bottleneck link side
243 
244  if (queueDiscType == "PfifoFast")
245  {
246  tch1.SetRootQueueDisc("ns3::PfifoFastQueueDisc", "MaxSize", StringValue("1000p"));
247  }
248  else if (queueDiscType == "ARED")
249  {
250  tch1.SetRootQueueDisc("ns3::RedQueueDisc");
251  Config::SetDefault("ns3::RedQueueDisc::ARED", BooleanValue(true));
252  Config::SetDefault("ns3::RedQueueDisc::MaxSize",
253  QueueSizeValue(QueueSize(QueueSizeUnit::BYTES, 1000000)));
254  Config::SetDefault("ns3::RedQueueDisc::MeanPktSize", UintegerValue(1000));
255  Config::SetDefault("ns3::RedQueueDisc::LinkBandwidth", StringValue("100Mbps"));
256  Config::SetDefault("ns3::RedQueueDisc::MinTh", DoubleValue(83333));
257  Config::SetDefault("ns3::RedQueueDisc::MinTh", DoubleValue(250000));
258  }
259  else if (queueDiscType == "CoDel")
260  {
261  tch1.SetRootQueueDisc("ns3::CoDelQueueDisc");
262  }
263  else if (queueDiscType == "FqCoDel")
264  {
265  tch1.SetRootQueueDisc("ns3::FqCoDelQueueDisc");
266  }
267  else if (queueDiscType == "PIE")
268  {
269  tch1.SetRootQueueDisc("ns3::PieQueueDisc");
270  Config::SetDefault("ns3::PieQueueDisc::MaxSize",
271  QueueSizeValue(QueueSize(QueueSizeUnit::PACKETS, 1000)));
272  Config::SetDefault("ns3::PieQueueDisc::QueueDelayReference", TimeValue(Seconds(0.02)));
273  Config::SetDefault("ns3::PieQueueDisc::Tupdate", TimeValue(Seconds(0.032)));
274  Config::SetDefault("ns3::PieQueueDisc::A", DoubleValue(2));
275  Config::SetDefault("ns3::PieQueueDisc::B", DoubleValue(20));
276  }
277  else
278  {
279  NS_ABORT_MSG("--queueDiscType not valid");
280  }
281 
282  if (bql)
283  {
284  tch1.SetQueueLimits("ns3::DynamicQueueLimits");
285  }
286 
287  QueueDiscContainer qdiscs = tch1.Install(devices1);
288  Ptr<QueueDisc> q = qdiscs.Get(0);
289 
290  if (writer)
291  {
292  AsciiTraceHelper ascii;
293  Ptr<OutputStreamWrapper> stream =
294  ascii.CreateFileStream("exp-" + std::to_string(index) + "-router-tc-stats.txt");
295  Simulator::Schedule(Seconds(0.001), &TcPacketsInQueue, q, stream);
296 
297 #ifdef HAVE_NETMAP_USER_H
298  if (emuMode.compare("netmap") == 0)
299  {
300  Ptr<NetmapNetDevice> dev = StaticCast<NetmapNetDevice>(device1);
301  Ptr<OutputStreamWrapper> stream2 =
302  ascii.CreateFileStream("exp-" + std::to_string(index) + "-router-inflight.txt");
303  Simulator::Schedule(Seconds(0.001), &Inflight, dev, stream2);
304  }
305 #endif
306 
307  Ptr<OutputStreamWrapper> routingStream =
308  Create<OutputStreamWrapper>("router-routes.txt", std::ios::out);
310  }
311 
312  NS_LOG_INFO("Run Emulation.");
313  Simulator::Stop(Seconds(50.0));
314  Simulator::Run();
316  delete helper0;
317  delete helper1;
318  NS_LOG_INFO("Done.");
319 
320  return 0;
321 }
Manage ASCII trace files for device models.
Definition: trace-helper.h:174
Ptr< OutputStreamWrapper > CreateFileStream(std::string filename, std::ios::openmode filemode=std::ios::out)
Create and initialize an output stream object we'll use to write the traced bits.
Parse command-line arguments.
Definition: command-line.h:232
This class can be used to hold variables of floating point type such as 'double' or 'float'.
Definition: double.h:42
build a set of FdNetDevice objects attached to a physical network interface
void SetDeviceName(std::string deviceName)
Set the device name of this device.
build a set of FdNetDevice objects Normally we eschew multiple inheritance, however,...
virtual NetDeviceContainer Install(Ptr< Node > node) const
This method creates a FdNetDevice and associates it to a node.
static void Bind(std::string name, const AttributeValue &value)
Iterate over the set of GlobalValues until a matching name is found and then set its value with Globa...
aggregate IP/TCP/UDP functionality to existing Nodes.
void Install(std::string nodeName) const
Aggregate implementations of the ns3::Ipv4, ns3::Ipv6, ns3::Udp, and ns3::Tcp classes onto the provid...
Ipv4 addresses are stored in host order in this class.
Definition: ipv4-address.h:42
static void PopulateRoutingTables()
Build a routing database and initialize the routing tables of the nodes in the simulation.
Access to the IPv4 forwarding table, interfaces, and configuration.
Definition: ipv4.h:80
a class to store IPv4 address information on an interface
a class to represent an Ipv4 address mask
Definition: ipv4-address.h:257
static void PrintRoutingTableAllAt(Time printTime, Ptr< OutputStreamWrapper > stream, Time::Unit unit=Time::S)
prints the routing tables of all nodes at a particular time.
holds a vector of ns3::NetDevice pointers
Ptr< NetDevice > Get(uint32_t i) const
Get the Ptr<NetDevice> stored in this container at a given index.
build a set of FdNetDevice objects attached to a physical network interface
void SetDeviceName(std::string deviceName)
Set the device name of this device.
Ptr< T > GetObject() const
Get a pointer to the requested aggregated Object.
Definition: object.h:471
std::ostream * GetStream()
Return a pointer to an ostream previously set in the wrapper.
Holds a vector of ns3::QueueDisc pointers.
Ptr< QueueDisc > Get(std::size_t i) const
Get the Ptr<QueueDisc> stored in this container at a given index.
uint32_t GetNPackets() const
Get the number of packets stored by the queue disc.
Definition: queue-disc.cc:432
uint32_t GetNBytes() const
Get the amount of bytes stored by the queue disc.
Definition: queue-disc.cc:439
const Stats & GetStats()
Retrieve all the collected statistics.
Definition: queue-disc.cc:412
Class for representing queue sizes.
Definition: queue-size.h:96
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition: simulator.h:571
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
Definition: simulator.cc:142
static Time Now()
Return the current simulation virtual time.
Definition: simulator.cc:208
static void Run()
Run the simulation.
Definition: simulator.cc:178
static void Stop()
Tell the Simulator the calling event should be the last one executed.
Definition: simulator.cc:186
Hold variables of type string.
Definition: string.h:56
double GetSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:403
Build a set of QueueDisc objects.
QueueDiscContainer Install(NetDeviceContainer c)
uint16_t SetRootQueueDisc(const std::string &type, Args &&... args)
Helper function used to set a root queue disc of the given type and with the given attributes.
void SetQueueLimits(std::string type, Args &&... args)
Helper function used to add a queue limits object to the transmission queues of the devices.
Hold an unsigned integer type.
Definition: uinteger.h:45
void TcPacketsInQueue(Ptr< QueueDisc > q, Ptr< OutputStreamWrapper > stream)
Definition: fd-emu-tc.cc:56
void SetDefault(std::string name, const AttributeValue &value)
Definition: config.cc:890
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition: abort.h:49
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition: log.h:275
@ BYTES
Use number of bytes for queue size.
Definition: queue-size.h:46
@ PACKETS
Use number of packets for queue size.
Definition: queue-size.h:45
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1326
const double m1
First component modulus, 232 - 209.
Definition: rng-stream.cc:60
NLOHMANN_BASIC_JSON_TPL_DECLARATION std::string to_string(const NLOHMANN_BASIC_JSON_TPL &j)
user-defined to_string function for JSON values
Definition: json.h:25255
Every class exported by the ns3 library is enclosed in the ns3 namespace.
cmd
Definition: second.py:40
uint32_t nTotalDroppedPackets
Total dropped packets.
Definition: queue-disc.h:206
uint64_t nTotalDroppedBytes
Total dropped bytes.
Definition: queue-disc.h:216