A Discrete-Event Network Simulator
API
fd-emu-ping.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2012 University of Washington, 2012 INRIA
3  * 2017 Università' degli Studi di Napoli Federico II
4  * 2019 NITK Surathkal
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation;
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  */
19 
20 // Allow ns-3 to ping a real host somewhere, using emulation mode
21 //
22 // +--------------------------+
23 // | host |
24 // +--------------------------+
25 // | ns-3 simulation |
26 // +--------------------------+
27 // | ns-3 Node |
28 // | +--------------------+ |
29 // | | ns-3 TCP | |
30 // | +--------------------+ |
31 // | | ns-3 IPv4 | |
32 // | +--------------------+ |
33 // | | FdNetDevice or | |
34 // | | NetmapNetDevice or | |
35 // | | DpdkNetDevice | |
36 // |--+--------------------+--+
37 // | | eth0 | |
38 // | +------+ |
39 // | | |
40 // +------------|-------------+
41 // |
42 // | +---------+
43 // .-------| GW host |--- (Internet) -----
44 // +---------+
45 //
47 // 1) You need to decide on a physical device on your real system, and either
48 // overwrite the hard-configured device name below (eth0) or pass this
49 // device name in as a command-line argument
50 // 1') If you run emulation in dpdk mode, use device address (eg. 0000:00.1f.6)
51 // as device name. This address can be obtained by running `lspci`
52 // 2) The host device must be set to promiscuous mode
53 // (e.g. "sudo ip link set eth0 promisc on")
54 // 2') If you run emulation in netmap or dpdk mode, you need before to load
55 // the netmap.ko or dpdk modules. The user is in charge to configure and
56 // build netmap/dpdk separately.
57 // 3) Be aware that ns-3 will generate a fake mac address, and that in
58 // some enterprise networks, this may be considered bad form to be
59 // sending packets out of your device with "unauthorized" mac addresses
60 // 4) You will need to assign an IP address to the ns-3 simulation node that
61 // is consistent with the subnet that is active on the host device's link.
62 // That is, you will have to assign an IP address to the ns-3 node as if
63 // it were on your real subnet. Search for "Ipv4Address localIp" and
64 // replace the string "1.2.3.4" with a valid IP address.
65 // 5) You will need to configure a default route in the ns-3 node to tell it
66 // how to get off of your subnet. One thing you could do is a
67 // 'netstat -rn' command and find the IP address of the default gateway
68 // on your host. Search for "Ipv4Address gateway" and replace the string
69 // "1.2.3.4" string with the gateway IP address.
70 // 6) Give root suid to the raw or netmap socket creator binary.
71 // If the --enable-sudo option was used to configure ns-3 with ns3, then the following
72 // step will not be necessary.
73 //
74 // $ sudo chown root.root build/src/fd-net-device/ns3-dev-raw-sock-creator
75 // $ sudo chmod 4755 build/src/fd-net-device/ns3-dev-raw-sock-creator
76 //
77 // or (if you run emulation in netmap mode):
78 // $ sudo chown root.root build/src/fd-net-device/ns3-dev-netmap-device-creator
79 // $ sudo chmod 4755 build/src/fd-net-device/ns3-dev-netmap-device-creator
80 // 6') If you run emulation in dpdk mode, you will need to run example as root.
81 //
82 
83 #include "ns3/abort.h"
84 #include "ns3/core-module.h"
85 #include "ns3/fd-net-device-module.h"
86 #include "ns3/internet-apps-module.h"
87 #include "ns3/internet-module.h"
88 #include "ns3/ipv4-list-routing-helper.h"
89 #include "ns3/ipv4-static-routing-helper.h"
90 #include "ns3/network-module.h"
91 
92 using namespace ns3;
93 
94 NS_LOG_COMPONENT_DEFINE("PingEmulationExample");
95 
96 static void
97 PingRtt(std::string context, uint16_t seqNo, Time rtt)
98 {
99  NS_LOG_UNCOND("Received " << seqNo << " Response with RTT = " << rtt);
100 }
101 
102 int
103 main(int argc, char* argv[])
104 {
105  NS_LOG_INFO("Ping Emulation Example");
106 
107  std::string deviceName("eth0");
108  std::string remote("8.8.8.8");
109  std::string localAddress("1.2.3.4");
110  std::string localGateway("1.2.3.4");
111 #ifdef HAVE_PACKET_H
112  std::string emuMode("raw");
113 #elif HAVE_NETMAP_USER_H
114  std::string emuMode("netmap");
115 #else // HAVE_DPDK_USER_H is true (otherwise this example is not compiled)
116  std::string emuMode("dpdk");
117 #endif
118 
119  //
120  // Allow the user to override any of the defaults at run-time, via
121  // command-line arguments
122  //
123  CommandLine cmd(__FILE__);
124  cmd.AddValue("deviceName",
125  "Device name (in raw, netmap mode) or Device address (in dpdk mode, eg: "
126  "0000:00:1f.6). Use `lspci` to find device address.",
127  deviceName);
128  cmd.AddValue("remote", "Remote IP address (dotted decimal only please)", remote);
129  cmd.AddValue("localIp", "Local IP address (dotted decimal only please)", localAddress);
130  cmd.AddValue("gateway", "Gateway address (dotted decimal only please)", localGateway);
131  cmd.AddValue("emuMode", "Emulation mode in {raw, netmap, dpdk}", emuMode);
132  cmd.Parse(argc, argv);
133 
134  Ipv4Address remoteIp(remote.c_str());
135  Ipv4Address localIp(localAddress.c_str());
136  NS_ABORT_MSG_IF(localIp == "1.2.3.4",
137  "You must change the local IP address before running this example");
138 
139  Ipv4Mask localMask("255.255.255.0");
140 
141  //
142  // Since we are using a real piece of hardware we need to use the realtime
143  // simulator.
144  //
145  GlobalValue::Bind("SimulatorImplementationType", StringValue("ns3::RealtimeSimulatorImpl"));
146 
147  //
148  // Since we are going to be talking to real-world machines, we need to enable
149  // calculation of checksums in our protocols.
150  //
151  GlobalValue::Bind("ChecksumEnabled", BooleanValue(true));
152 
153  //
154  // In such a simple topology, the use of the helper API can be a hindrance
155  // so we drop down into the low level API and do it manually.
156  //
157  // First we need a single node.
158  //
159  NS_LOG_INFO("Create Node");
160  Ptr<Node> node = CreateObject<Node>();
161 
162  //
163  // Create an emu device, allocate a MAC address and point the device to the
164  // Linux device name. The device needs a transmit queueing discipline so
165  // create a droptail queue and give it to the device. Finally, "install"
166  // the device into the node.
167  //
168  // Do understand that the ns-3 allocated MAC address will be sent out over
169  // your network since the emu net device will spoof it. By default, this
170  // address will have an Organizationally Unique Identifier (OUI) of zero.
171  // The Internet Assigned Number Authority IANA
172  //
173  // http://www.iana.org/assignments/ethernet-numbers
174  //
175  // reports that this OUI is unassigned, and so should not conflict with
176  // real hardware on your net. It may raise all kinds of red flags in a
177  // real environment to have packets from a device with an obviously bogus
178  // OUI flying around. Be aware.
179  //
180  NS_LOG_INFO("Create Device");
181 
182  FdNetDeviceHelper* helper = nullptr;
183 
184 #ifdef HAVE_PACKET_H
185  if (emuMode == "raw")
186  {
187  auto raw = new EmuFdNetDeviceHelper;
188  raw->SetDeviceName(deviceName);
189  helper = raw;
190  }
191 #endif
192 #ifdef HAVE_NETMAP_USER_H
193  if (emuMode == "netmap")
194  {
196  netmap->SetDeviceName(deviceName);
197  helper = netmap;
198  }
199 #endif
200 #ifdef HAVE_DPDK_USER_H
201  if (emuMode == "dpdk")
202  {
204  // Use e1000 driver library (this is for IGb PMD supporting Intel 1GbE NIC)
205  // NOTE: DPDK supports multiple Poll Mode Drivers (PMDs) and you can use it
206  // based on your NIC. You just need to set pmd library as follows:
207  dpdk->SetPmdLibrary("librte_pmd_e1000.so");
208  // Set dpdk driver to use for the NIC. `uio_pci_generic` supports most NICs.
209  dpdk->SetDpdkDriver("uio_pci_generic");
210  // Set device name
211  dpdk->SetDeviceName(deviceName);
212  helper = dpdk;
213  }
214 #endif
215 
216  if (helper == nullptr)
217  {
218  NS_ABORT_MSG(emuMode << " not supported.");
219  }
220 
221  NetDeviceContainer devices = helper->Install(node);
222  Ptr<NetDevice> device = devices.Get(0);
223  device->SetAttribute("Address", Mac48AddressValue(Mac48Address::Allocate()));
224 
225  // Ptr<Queue> queue = CreateObject<DropTailQueue> ();
226  // device->SetQueue (queue);
227  // node->AddDevice (device);
228 
229  //
230  // Add a default internet stack to the node. This gets us the ns-3 versions
231  // of ARP, IPv4, ICMP, UDP and TCP.
232  //
233  NS_LOG_INFO("Add Internet Stack");
234  InternetStackHelper internetStackHelper;
235  internetStackHelper.Install(node);
236 
237  NS_LOG_INFO("Create IPv4 Interface");
238  Ptr<Ipv4> ipv4 = node->GetObject<Ipv4>();
239  uint32_t interface = ipv4->AddInterface(device);
240  Ipv4InterfaceAddress address = Ipv4InterfaceAddress(localIp, localMask);
241  ipv4->AddAddress(interface, address);
242  ipv4->SetMetric(interface, 1);
243  ipv4->SetUp(interface);
244 
245  //
246  // When the ping application sends its ICMP packet, it will happily send it
247  // down the ns-3 protocol stack. We set the IP address of the destination
248  // to the address corresponding to example.com above. This address is off
249  // our local network so we have got to provide some kind of default route
250  // to ns-3 to be able to get that ICMP packet forwarded off of our network.
251  //
252  // You have got to provide an IP address of a real host that you can send
253  // real packets to and have them forwarded off of your local network. One
254  // thing you could do is a 'netstat -rn' command and find the IP address of
255  // the default gateway on your host and add it below, replacing the
256  // "1.2.3.4" string.
257  //
258  Ipv4Address gateway(localGateway.c_str());
259  NS_ABORT_MSG_IF(gateway == "1.2.3.4",
260  "You must change the gateway IP address before running this example");
261 
262  Ipv4StaticRoutingHelper ipv4RoutingHelper;
263  Ptr<Ipv4StaticRouting> staticRouting = ipv4RoutingHelper.GetStaticRouting(ipv4);
264  staticRouting->SetDefaultRoute(gateway, interface);
265 
266  //
267  // Create the ping application. This application knows how to send
268  // ICMP echo requests. Setting up the packet sink manually is a bit
269  // of a hassle and since there is no law that says we cannot mix the
270  // helper API with the low level API, let's just use the helper.
271  //
272  NS_LOG_INFO("Create Ping Application");
273  Ptr<Ping> app = CreateObject<Ping>();
274  app->SetAttribute("Destination", AddressValue(remoteIp));
275  app->SetAttribute("VerboseMode", EnumValue(Ping::VerboseMode::VERBOSE));
276  node->AddApplication(app);
277  app->SetStartTime(Seconds(1.0));
278  app->SetStopTime(Seconds(22.0));
279 
280  //
281  // Give the application a name. This makes life much easier when constructing
282  // config paths.
283  //
284  Names::Add("app", app);
285 
286  //
287  // Hook a trace to print something when the response comes back.
288  //
289  Config::Connect("/Names/app/Rtt", MakeCallback(&PingRtt));
290 
291  //
292  // Enable a promiscuous pcap trace to see what is coming and going on our device.
293  //
294  helper->EnablePcap(emuMode + "-emu-ping", device, true);
295 
296  //
297  // Now, do the actual emulation.
298  //
299  NS_LOG_INFO("Run Emulation in " << emuMode << " mode.");
300  Simulator::Stop(Seconds(23.0));
301  Simulator::Run();
303  delete helper;
304  NS_LOG_INFO("Done.");
305 
306  return 0;
307 }
Parse command-line arguments.
Definition: command-line.h:232
build a DpdkNetDevice object attached to a physical network interface
void SetPmdLibrary(std::string pmdLibrary)
Sets PMD Library to be used for the NIC.
void SetDpdkDriver(std::string dpdkDriver)
Sets DPDK Driver to bind NIC to.
build a set of FdNetDevice objects attached to a physical network interface
void SetDeviceName(std::string deviceName)
Set the device name of this device.
Hold variables of type enum.
Definition: enum.h:62
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
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
Helper class that adds ns3::Ipv4StaticRouting objects.
Ptr< Ipv4StaticRouting > GetStaticRouting(Ptr< Ipv4 > ipv4) const
Try and find the static routing protocol as either the main routing protocol or in the list of routin...
static Mac48Address Allocate()
Allocate a new Mac48Address.
static void Add(std::string name, Ptr< Object > object)
Add the association between the string "name" and the Ptr<Object> obj.
Definition: names.cc:775
holds a vector of ns3::NetDevice pointers
build a set of FdNetDevice objects attached to a physical network interface
void SetDeviceName(std::string deviceName)
Set the device name of this device.
uint32_t AddApplication(Ptr< Application > application)
Associate an Application to this Node.
Definition: node.cc:169
Ptr< T > GetObject() const
Get a pointer to the requested aggregated Object.
Definition: object.h:471
void EnablePcap(std::string prefix, Ptr< NetDevice > nd, bool promiscuous=false, bool explicitFilename=false)
Enable pcap output the indicated net device.
static void Destroy()
Execute the events scheduled with ScheduleDestroy().
Definition: simulator.cc:142
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
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
static void PingRtt(std::string context, uint16_t seqNo, Time rtt)
Definition: fd-emu-ping.cc:97
void Connect(std::string path, const CallbackBase &cb)
Definition: config.cc:974
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition: abort.h:49
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition: abort.h:108
#define NS_LOG_UNCOND(msg)
Output the requested message unconditionally.
#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
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1326
address
Definition: first.py:47
devices
Definition: first.py:42
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Callback< R, Args... > MakeCallback(R(T::*memPtr)(Args...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition: callback.h:704
cmd
Definition: second.py:40