remove deprecated emu module
This commit is contained in:
@@ -34,7 +34,6 @@ SOURCES = \
|
||||
$(SRC)/csma/doc/csma.rst \
|
||||
$(SRC)/dsdv/doc/dsdv.rst \
|
||||
$(SRC)/dsr/doc/dsr.rst \
|
||||
$(SRC)/emu/doc/emu.rst \
|
||||
$(SRC)/mpi/doc/distributed.rst \
|
||||
$(SRC)/energy/doc/energy.rst \
|
||||
$(SRC)/fd-net-device/doc/fd-net-device.rst \
|
||||
|
||||
@@ -18,8 +18,7 @@ any combination of simulated or emulated devices.
|
||||
|
||||
**Note:** Prior to ns-3.17, the emulation capability was provided by a
|
||||
special device called an ``Emu`` NetDevice; the ``Emu`` NetDevice has
|
||||
been superseded by the ``FdNetDevice``, and will be deprecated and removed
|
||||
in future revisions of |ns3|.
|
||||
been replaced by the ``FdNetDevice``.
|
||||
|
||||
One of the use-cases we want to support is that of a testbed. A concrete example
|
||||
of an environment of this kind is the ORBIT testbed. ORBIT is a laboratory
|
||||
@@ -83,6 +82,5 @@ simulated |ns3| networks.
|
||||
|
||||
.. toctree::
|
||||
|
||||
emu
|
||||
fd-net-device
|
||||
tap
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
callback_classes = [
|
||||
['void', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty'],
|
||||
['bool', 'ns3::Ptr<ns3::NetDevice>', 'ns3::Ptr<ns3::Packet const>', 'unsigned short', 'ns3::Address const&', 'ns3::Address const&', 'ns3::NetDevice::PacketType', 'ns3::empty', 'ns3::empty', 'ns3::empty'],
|
||||
['bool', 'ns3::Ptr<ns3::NetDevice>', 'ns3::Ptr<ns3::Packet const>', 'unsigned short', 'ns3::Address const&', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty'],
|
||||
['void', 'ns3::Ptr<ns3::NetDevice>', 'ns3::Ptr<ns3::Packet const>', 'unsigned short', 'ns3::Address const&', 'ns3::Address const&', 'ns3::NetDevice::PacketType', 'ns3::empty', 'ns3::empty', 'ns3::empty'],
|
||||
]
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,10 +0,0 @@
|
||||
import os
|
||||
|
||||
def post_register_types(root_module):
|
||||
enabled_features = os.environ['NS3_ENABLED_FEATURES'].split(',')
|
||||
|
||||
if 'EmuNetDevice' not in enabled_features:
|
||||
for clsname in ['EmuNetDevice', 'EmuHelper']:
|
||||
root_module.classes.remove(root_module['ns3::%s' % clsname])
|
||||
root_module.enums.remove(root_module['ns3::EmuNetDevice::EncapsulationMode'])
|
||||
|
||||
@@ -1,316 +0,0 @@
|
||||
.. include:: replace.txt
|
||||
.. highlight:: cpp
|
||||
|
||||
Emu NetDevice
|
||||
-------------
|
||||
|
||||
**Note:** The ``EmuNetDevice`` is being deprecated as of ns-3.17. The
|
||||
:doc:`fd-net-device` and ``EmuFdNetDeviceHelper`` class replaces this functionality and API entirely.
|
||||
|
||||
Behavior
|
||||
********
|
||||
|
||||
The ``Emu`` net device allows a simulation node to send and receive packets over
|
||||
a real network. The emulated net device relies on a specified interface being in
|
||||
promiscuous mode. It opens a raw socket and binds to that interface. We perform
|
||||
MAC spoofing to separate simulation network traffic from other
|
||||
network traffic that may be flowing to and from the host.
|
||||
|
||||
One can use the ``Emu`` net device in a testbed situation where the host on
|
||||
which the simulation is running has a specific interface of interest which
|
||||
drives the testbed hardware. You would also need to set this specific interface
|
||||
into promiscuous mode and provide an appropriate device name to the |ns3|
|
||||
emulated net device. An example of this environment is the ORBIT testbed as
|
||||
described above.
|
||||
|
||||
The ``Emu`` net device only works if the underlying interface is up and in
|
||||
promiscuous mode. Packets will be sent out over the device, but we use MAC
|
||||
spoofing. The MAC addresses will be generated (by default) using the
|
||||
Organizationally Unique Identifier (OUI) 00:00:00 as a base. This vendor code is
|
||||
not assigned to any organization and so should not conflict with any real
|
||||
hardware.
|
||||
|
||||
It is always up to the user to determine that using these MAC addresses is okay
|
||||
on your network and won't conflict with anything else (including another
|
||||
simulation using ``Emu`` devices) on your network. If you are using the emulated
|
||||
net device in separate simulations you must consider global MAC address
|
||||
assignment issues and ensure that MAC addresses are unique across all
|
||||
simulations. The emulated net device respects the MAC address provided in the
|
||||
``SetAddress`` method so you can do this manually. For larger simulations, you
|
||||
may want to set the OUI in the MAC address allocation function.
|
||||
|
||||
IP addresses corresponding to the emulated net devices are the addresses
|
||||
generated in the simulation, which are generated in the usual way via helper
|
||||
functions. Since we are using MAC spoofing, there will not be a conflict between
|
||||
|ns3| network stacks and any native network stacks.
|
||||
|
||||
The emulated net device comes with a helper function as all |ns3| devices do.
|
||||
One unique aspect is that there is no channel associated with the underlying
|
||||
medium. We really have no idea what this external medium is, and so have not
|
||||
made an effort to model it abstractly. The primary thing to be aware of is the
|
||||
implication this has for IPv4 global routing. The global router module attempts
|
||||
to walk the channels looking for adjacent networks. Since there is no channel,
|
||||
the global router will be unable to do this and you must then use a dynamic
|
||||
routing protocol such as OLSR to include routing in ``Emu``-based networks.
|
||||
|
||||
Usage
|
||||
*****
|
||||
|
||||
Any mixing of |ns3| objects with real objects will typically require that
|
||||
|ns3| compute checksums in its protocols. By default, checksums are not
|
||||
computed by |ns3|. To enable checksums (e.g. UDP, TCP, IP), users must set
|
||||
the attribute ``ChecksumEnabled`` to true, such as follows::
|
||||
|
||||
GlobalValue::Bind ("ChecksumEnabled", BooleanValue (true));
|
||||
|
||||
The usage of the ``Emu`` net device is straightforward once the network of
|
||||
simulations has been configured. Since most of the work involved in working with
|
||||
this device is in network configuration before even starting a simulation, you
|
||||
may want to take a moment to review a couple of HOWTO pages on the |ns3| wiki
|
||||
that describe how to set up a virtual test network using VMware and how to run a
|
||||
set of example (client server) simulations that use ``Emu`` net devices.
|
||||
|
||||
* `<http://www.nsnam.org/wiki/HOWTO_use_VMware_to_set_up_virtual_networks_(Windows)>`_
|
||||
* `<http://www.nsnam.org/wiki/HOWTO_use_ns-3_scripts_to_drive_real_hardware_(experimental)>`_
|
||||
|
||||
Once you are over the configuration hurdle, the script changes required to use
|
||||
an ``Emu`` device are trivial. The main structural difference is that you will
|
||||
need to create an |ns3| simulation script for each node. In the case of the
|
||||
HOWTOs above, there is one client script and one server script. The only
|
||||
"challenge" is to get the addresses set correctly.
|
||||
|
||||
Just as with all other |ns3| net devices, we provide a helper class for the
|
||||
``Emu`` net device. The following code snippet illustrates how one would declare
|
||||
an EmuHelper and use it to set the "DeviceName" attribute to "eth1" and install
|
||||
``Emu`` devices on a group of nodes. You would do this on both the client and
|
||||
server side in the case of the HOWTO seen above.::
|
||||
|
||||
EmuHelper emu;
|
||||
emu.SetAttribute ("DeviceName", StringValue ("eth1"));
|
||||
NetDeviceContainer d = emu.Install (n);
|
||||
|
||||
The only other change that may be required is to make sure that the address
|
||||
spaces (MAC and IP) on the client and server simulations are compatible. First
|
||||
the MAC address is set to a unique well-known value in both places (illustrated
|
||||
here for one side).::
|
||||
|
||||
//
|
||||
// We've got the devices in place. Since we're using MAC address
|
||||
// spoofing under the sheets, we need to make sure that the MAC addresses
|
||||
// we have assigned to our devices are unique. Ns-3 will happily
|
||||
// automatically assign the same MAC address to the devices in both halves
|
||||
// of our two-script pair, so let's go ahead and just manually change them
|
||||
// to something we ensure is unique.
|
||||
//
|
||||
Ptr<NetDevice> nd = d.Get (0);
|
||||
Ptr<EmuNetDevice> ed = nd->GetObject<EmuNetDevice> ();
|
||||
ed->SetAddress ("00:00:00:00:00:02");
|
||||
|
||||
And then the IP address of the client or server is set in the usual way using
|
||||
helpers.::
|
||||
|
||||
//
|
||||
// We've got the "hardware" in place. Now we need to add IP addresses.
|
||||
// This is the server half of a two-script pair. We need to make sure
|
||||
// that the addressing in both of these applications is consistent, so
|
||||
// we use provide an initial address in both cases. Here, the client
|
||||
// will reside on one machine running ns-3 with one node having ns-3
|
||||
// with IP address "10.1.1.2" and talk to a server script running in
|
||||
// another ns-3 on another computer that has an ns-3 node with IP
|
||||
// address "10.1.1.3"
|
||||
//
|
||||
Ipv4AddressHelper ipv4;
|
||||
ipv4.SetBase ("10.1.1.0", "255.255.255.0", "0.0.0.2");
|
||||
Ipv4InterfaceContainer i = ipv4.Assign (d);
|
||||
|
||||
You will use application helpers to generate traffic exactly as you do in any
|
||||
|ns3| simulation script. Note that the server address shown below in a snippet
|
||||
from the client, must correspond to the IP address assigned to the server node
|
||||
similarly to the snippet above.::
|
||||
|
||||
uint32_t packetSize = 1024;
|
||||
uint32_t maxPacketCount = 2000;
|
||||
Time interPacketInterval = Seconds (0.001);
|
||||
UdpEchoClientHelper client ("10.1.1.3", 9);
|
||||
client.SetAttribute ("MaxPackets", UintegerValue (maxPacketCount));
|
||||
client.SetAttribute ("Interval", TimeValue (interPacketInterval));
|
||||
client.SetAttribute ("PacketSize", UintegerValue (packetSize));
|
||||
ApplicationContainer apps = client.Install (n.Get (0));
|
||||
apps.Start (Seconds (1.0));
|
||||
apps.Stop (Seconds (2.0));
|
||||
|
||||
The ``Emu`` net device and helper provide access to ASCII and pcap tracing
|
||||
functionality just as other |ns3| net devices to. You enable tracing similarly
|
||||
to these other net devices::
|
||||
|
||||
EmuHelper::EnablePcapAll ("emu-udp-echo-client");
|
||||
|
||||
For examples that use the ``Emu`` net device, see
|
||||
``src/emu/examples/emu-udp-echo.cc`` and ``src/emu/examples/emu-ping.cc``
|
||||
in the repository.
|
||||
|
||||
Implementation
|
||||
**************
|
||||
|
||||
Perhaps the most unusual part of the ``Emu`` and ``Tap`` device implementation
|
||||
relates to the requirement for executing some of the code with super-user
|
||||
permissions. Rather than force the user to execute the entire simulation as
|
||||
root, we provide a small "creator" program that runs as root and does any
|
||||
required high-permission sockets work.
|
||||
|
||||
We do a similar thing for both the ``Emu`` and the ``Tap`` devices. The
|
||||
high-level view is that the ``CreateSocket`` method creates a local interprocess
|
||||
(Unix) socket, forks, and executes the small creation program. The small
|
||||
program, which runs as suid root, creates a raw socket and sends back the raw
|
||||
socket file descriptor over the Unix socket that is passed to it as a parameter.
|
||||
The raw socket is passed as a control message (sometimes called ancillary data)
|
||||
of type SCM_RIGHTS.
|
||||
|
||||
The ``Emu`` net device uses the |ns3| threading and multithreaded real-time
|
||||
scheduler extensions. The interesting work in the ``Emu`` device is done when
|
||||
the net device is started (``EmuNetDevice::StartDevice ()``). An attribute
|
||||
("Start") provides a simulation time at which to spin up the net device. At this
|
||||
specified time (which defaults to t=0), the socket creation function is called
|
||||
and executes as described above. You may also specify a time at which to stop
|
||||
the device using the "Stop" attribute.
|
||||
|
||||
Once the (promiscuous mode) socket is created, we bind it to an interface name
|
||||
also provided as an attribute ("DeviceName") that is stored internally as
|
||||
``m_deviceName``::
|
||||
|
||||
struct ifreq ifr;
|
||||
bzero (&ifr, sizeof(ifr));
|
||||
strncpy ((char *)ifr.ifr_name, m_deviceName.c_str (), IFNAMSIZ);
|
||||
|
||||
int32_t rc = ioctl (m_sock, SIOCGIFINDEX, &ifr);
|
||||
|
||||
struct sockaddr_ll ll;
|
||||
bzero (&ll, sizeof(ll));
|
||||
|
||||
ll.sll_family = AF_PACKET;
|
||||
ll.sll_ifindex = m_sll_ifindex;
|
||||
ll.sll_protocol = htons(ETH_P_ALL);
|
||||
|
||||
rc = bind (m_sock, (struct sockaddr *)&ll, sizeof (ll));
|
||||
|
||||
After the promiscuous raw socket is set up, a separate thread is spawned to do
|
||||
reads from that socket and the link state is set to ``Up``.::
|
||||
|
||||
m_readThread = Create<SystemThread> (
|
||||
MakeCallback (&EmuNetDevice::ReadThread, this));
|
||||
m_readThread->Start ();
|
||||
|
||||
NotifyLinkUp ();
|
||||
|
||||
The ``EmuNetDevice::ReadThread`` function basically just sits in an infinite
|
||||
loop reading from the promiscuous mode raw socket and scheduling packet
|
||||
receptions using the real-time simulator extensions.::
|
||||
|
||||
for (;;)
|
||||
{
|
||||
...
|
||||
|
||||
len = recvfrom (m_sock, buf, bufferSize, 0, (struct sockaddr *)&addr,
|
||||
&addrSize);
|
||||
|
||||
...
|
||||
|
||||
DynamicCast<RealtimeSimulatorImpl> (Simulator::GetImplementation ())->
|
||||
ScheduleRealtimeNow (
|
||||
MakeEvent (&EmuNetDevice::ForwardUp, this, buf, len));
|
||||
|
||||
...
|
||||
}
|
||||
|
||||
The line starting with our templated DynamicCast function probably deserves a
|
||||
comment. It gains access to the simulator implementation object using the
|
||||
``Simulator::GetImplementation`` method and then casts to the real-time
|
||||
simulator implementation to use the real-time schedule method
|
||||
``ScheduleRealtimeNow``. This function will cause a handler for the newly
|
||||
received packet to be scheduled for execution at the current real time clock
|
||||
value. This will, in turn cause the simulation clock to be advanced to that real
|
||||
time value when the scheduled event (``EmuNetDevice::ForwardUp``) is fired.
|
||||
|
||||
The ``ForwardUp`` function operates as most other similar |ns3| net device
|
||||
methods do. The packet is first filtered based on the destination address. In
|
||||
the case of the ``Emu`` device, the MAC destination address will be the address
|
||||
of the ``Emu`` device and not the hardware address of the real device. Headers
|
||||
are then stripped off and the trace hooks are hit. Finally, the packet is passed
|
||||
up the |ns3| protocol stack using the receive callback function of the net
|
||||
device.
|
||||
|
||||
Sending a packet is equally straightforward as shown below. The first thing we
|
||||
do is to add the ethernet header and trailer to the |ns3| ``Packet`` we are
|
||||
sending. The source address corresponds to the address of the ``Emu`` device and
|
||||
not the underlying native device MAC address. This is where the MAC address
|
||||
spoofing is done. The trailer is added and we enqueue and dequeue the packet
|
||||
from the net device queue to hit the trace hooks.::
|
||||
|
||||
header.SetSource (source);
|
||||
header.SetDestination (destination);
|
||||
header.SetLengthType (packet->GetSize ());
|
||||
packet->AddHeader (header);
|
||||
|
||||
EthernetTrailer trailer;
|
||||
trailer.CalcFcs (packet);
|
||||
packet->AddTrailer (trailer);
|
||||
|
||||
m_queue->Enqueue (packet);
|
||||
packet = m_queue->Dequeue ();
|
||||
|
||||
struct sockaddr_ll ll;
|
||||
bzero (&ll, sizeof (ll));
|
||||
|
||||
ll.sll_family = AF_PACKET;
|
||||
ll.sll_ifindex = m_sll_ifindex;
|
||||
ll.sll_protocol = htons(ETH_P_ALL);
|
||||
|
||||
rc = sendto (m_sock, packet->PeekData (), packet->GetSize (), 0,
|
||||
reinterpret_cast<struct sockaddr *> (&ll), sizeof (ll));
|
||||
|
||||
Finally, we simply send the packet to the raw socket which puts it out on the
|
||||
real network.
|
||||
|
||||
From the point of view of tracing in the net device, there are several
|
||||
interesting points to insert trace hooks. A convention inherited from other
|
||||
simulators is that packets destined for transmission onto attached networks
|
||||
pass through a single "transmit queue" in the net device. We provide trace
|
||||
hooks at this point in packet flow, which corresponds (abstractly) only to a
|
||||
transition from the network to data link layer, and call them collectively
|
||||
the device MAC hooks.
|
||||
|
||||
When a packet is sent to the Emu net device for transmission it always
|
||||
passes through the transmit queue. The transmit queue in the EmuNetDevice
|
||||
inherits from Queue, and therefore inherits three trace sources:
|
||||
|
||||
* An Enqueue operation source (see Queue::m_traceEnqueue);
|
||||
* A Dequeue operation source (see Queue::m_traceDequeue);
|
||||
* A Drop operation source (see Queue::m_traceDrop).
|
||||
|
||||
The upper-level (MAC) trace hooks for the EmuNetDevice are, in fact,
|
||||
exactly these three trace sources on the single transmit queue of the device.
|
||||
|
||||
The m_traceEnqueue event is triggered when a packet is placed on the transmit
|
||||
queue. This happens at the time that ns3::EmuNetDevice::Send or
|
||||
``ns3::EmuNetDevice::SendFrom`` is called by a higher layer to queue a
|
||||
packet for transmission.
|
||||
|
||||
The m_traceDequeue event is triggered when a packet is removed from the
|
||||
transmit queue. Dequeues from the transmit queue happen immediately after
|
||||
the packet was enqueued and only indicate that the packet is about to be
|
||||
sent to an underlying raw socket. The actual time at which the packet is
|
||||
sent out on the wire is not available.
|
||||
|
||||
Similar to the upper level trace hooks, there are trace hooks available at
|
||||
the lower levels of the net device. We call these the PHY hooks. These
|
||||
events fire from the device methods that talk directly to the underlying
|
||||
raw socket.
|
||||
|
||||
The trace source m_dropTrace is not used in the Emu net device since that
|
||||
is really the business of the underlying "real" device driver.
|
||||
|
||||
The other low-level trace source fires on reception of an accepted packet
|
||||
(see ``ns3::EmuNetDevice::m_rxTrace``). A packet is accepted if it is destined
|
||||
for the broadcast address, a multicast address, or to the MAC address
|
||||
assigned to the Emu net device.
|
||||
|
||||
@@ -1,218 +0,0 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
// Allow ns-3 to ping a real host somewhere, using emulation mode
|
||||
//
|
||||
// ------------
|
||||
// | node n0 |
|
||||
// | |
|
||||
// | --- |
|
||||
// | | | |
|
||||
// | |emu| |
|
||||
// | | | |
|
||||
// | --- |
|
||||
// | | |
|
||||
// ----|-------
|
||||
// |
|
||||
// (device on host system, set to promiscuous mode)
|
||||
// |
|
||||
// --------- (Internet) -------
|
||||
//
|
||||
// To use this example:
|
||||
// 1) You need to decide on a physical device on your real system, and either
|
||||
// overwrite the hard-configured device name below (eth0) or pass this
|
||||
// device name in as a command-line argument
|
||||
// 2) The host device must be set to promiscuous mode
|
||||
// (e.g. "sudo ifconfig eth0 promisc")
|
||||
// 3) Be aware that ns-3 will generate a fake mac address, and that in
|
||||
// some enterprise networks, this may be considered bad form to be
|
||||
// sending packets out of your device with "unauthorized" mac addresses
|
||||
// 4) You will need to assign an IP address to the ns-3 simulation node that
|
||||
// is consistent with the subnet that is active on the host device's link.
|
||||
// That is, you will have to assign an IP address to the ns-3 node as if
|
||||
// it were on your real subnet. Search for "Ipv4Address localIp" and
|
||||
// replace the string "1.2.3.4" with a valid IP address.
|
||||
// 5) You will need to configure a default route in the ns-3 node to tell it
|
||||
// how to get off of your subnet. One thing you could do is a
|
||||
// 'netstat -rn' command and find the IP address of the default gateway
|
||||
// on your host. Search for "Ipv4Address gateway" and replace the string
|
||||
// "1.2.3.4" string with the gateway IP address.
|
||||
|
||||
#include "ns3/abort.h"
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/internet-module.h"
|
||||
#include "ns3/network-module.h"
|
||||
#include "ns3/emu-module.h"
|
||||
#include "ns3/applications-module.h"
|
||||
#include "ns3/ipv4-static-routing-helper.h"
|
||||
#include "ns3/ipv4-list-routing-helper.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("PingEmulationExample");
|
||||
|
||||
static void
|
||||
PingRtt (std::string context, Time rtt)
|
||||
{
|
||||
NS_LOG_UNCOND ("Received Response with RTT = " << rtt);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
NS_LOG_INFO ("Ping Emulation Example");
|
||||
|
||||
std::string deviceName ("eth0");
|
||||
std::string remote ("208.77.188.166"); // example.com
|
||||
|
||||
//
|
||||
// Allow the user to override any of the defaults at run-time, via
|
||||
// command-line arguments
|
||||
//
|
||||
CommandLine cmd;
|
||||
cmd.AddValue ("deviceName", "Device name", deviceName);
|
||||
cmd.AddValue ("remote", "Remote IP address (dotted decimal only please)", remote);
|
||||
cmd.Parse (argc, argv);
|
||||
|
||||
Ipv4Address remoteIp (remote.c_str ());
|
||||
Ipv4Address localIp ("192.168.1.94");
|
||||
NS_ABORT_MSG_IF (localIp == "1.2.3.4", "You must change the local IP address before running this example");
|
||||
|
||||
Ipv4Mask localMask ("255.255.255.0");
|
||||
|
||||
//
|
||||
// Since we are using a real piece of hardware we need to use the realtime
|
||||
// simulator.
|
||||
//
|
||||
GlobalValue::Bind ("SimulatorImplementationType", StringValue ("ns3::RealtimeSimulatorImpl"));
|
||||
|
||||
//
|
||||
// Since we are going to be talking to real-world machines, we need to enable
|
||||
// calculation of checksums in our protocols.
|
||||
//
|
||||
GlobalValue::Bind ("ChecksumEnabled", BooleanValue (true));
|
||||
|
||||
//
|
||||
// In such a simple topology, the use of the helper API can be a hindrance
|
||||
// so we drop down into the low level API and do it manually.
|
||||
//
|
||||
// First we need a single node.
|
||||
//
|
||||
NS_LOG_INFO ("Create Node");
|
||||
Ptr<Node> node = CreateObject<Node> ();
|
||||
|
||||
//
|
||||
// Create an emu device, allocate a MAC address and point the device to the
|
||||
// Linux device name. The device needs a transmit queueing discipline so
|
||||
// create a droptail queue and give it to the device. Finally, "install"
|
||||
// the device into the node.
|
||||
//
|
||||
// Do understand that the ns-3 allocated MAC address will be sent out over
|
||||
// your network since the emu net device will spoof it. By default, this
|
||||
// address will have an Organizationally Unique Identifier (OUI) of zero.
|
||||
// The Internet Assigned Number Authority IANA
|
||||
//
|
||||
// http://www.iana.org/assignments/ethernet-numbers
|
||||
//
|
||||
// reports that this OUI is unassigned, and so should not conflict with
|
||||
// real hardware on your net. It may raise all kinds of red flags in a
|
||||
// real environment to have packets from a device with an obviously bogus
|
||||
// OUI flying around. Be aware.
|
||||
//
|
||||
NS_LOG_INFO ("Create Device");
|
||||
Ptr<EmuNetDevice> device = CreateObject<EmuNetDevice> ();
|
||||
device->SetAttribute ("Address", Mac48AddressValue (Mac48Address::Allocate ()));
|
||||
device->SetAttribute ("DeviceName", StringValue (deviceName));
|
||||
|
||||
Ptr<Queue> queue = CreateObject<DropTailQueue> ();
|
||||
device->SetQueue (queue);
|
||||
node->AddDevice (device);
|
||||
|
||||
//
|
||||
// Add a default internet stack to the node. This gets us the ns-3 versions
|
||||
// of ARP, IPv4, ICMP, UDP and TCP.
|
||||
//
|
||||
NS_LOG_INFO ("Add Internet Stack");
|
||||
InternetStackHelper internetStackHelper;
|
||||
internetStackHelper.Install (node);
|
||||
|
||||
NS_LOG_INFO ("Create IPv4 Interface");
|
||||
Ptr<Ipv4> ipv4 = node->GetObject<Ipv4> ();
|
||||
uint32_t interface = ipv4->AddInterface (device);
|
||||
Ipv4InterfaceAddress address = Ipv4InterfaceAddress (localIp, localMask);
|
||||
ipv4->AddAddress (interface, address);
|
||||
ipv4->SetMetric (interface, 1);
|
||||
ipv4->SetUp (interface);
|
||||
|
||||
//
|
||||
// When the ping appliation sends its ICMP packet, it will happily send it
|
||||
// down the ns-3 protocol stack. We set the IP address of the destination
|
||||
// to the address corresponding to example.com above. This address is off
|
||||
// our local network so we have got to provide some kind of default route
|
||||
// to ns-3 to be able to get that ICMP packet forwarded off of our network.
|
||||
//
|
||||
// You have got to provide an IP address of a real host that you can send
|
||||
// real packets to and have them forwarded off of your local network. One
|
||||
// thing you could do is a 'netstat -rn' command and find the IP address of
|
||||
// the default gateway on your host and add it below, replacing the
|
||||
// "1.2.3.4" string.
|
||||
//
|
||||
Ipv4Address gateway ("192.168.1.254");
|
||||
NS_ABORT_MSG_IF (gateway == "1.2.3.4", "You must change the gateway IP address before running this example");
|
||||
|
||||
Ipv4StaticRoutingHelper ipv4RoutingHelper;
|
||||
Ptr<Ipv4StaticRouting> staticRouting = ipv4RoutingHelper.GetStaticRouting (ipv4);
|
||||
staticRouting->SetDefaultRoute (gateway, interface);
|
||||
|
||||
//
|
||||
// Create the ping application. This application knows how to send
|
||||
// ICMP echo requests. Setting up the packet sink manually is a bit
|
||||
// of a hassle and since there is no law that says we cannot mix the
|
||||
// helper API with the low level API, let's just use the helper.
|
||||
//
|
||||
NS_LOG_INFO ("Create V4Ping Appliation");
|
||||
Ptr<V4Ping> app = CreateObject<V4Ping> ();
|
||||
app->SetAttribute ("Remote", Ipv4AddressValue (remoteIp));
|
||||
node->AddApplication (app);
|
||||
app->SetStartTime (Seconds (1.0));
|
||||
app->SetStopTime (Seconds (5.0));
|
||||
|
||||
//
|
||||
// Give the application a name. This makes life much easier when constructing
|
||||
// config paths.
|
||||
//
|
||||
Names::Add ("app", app);
|
||||
|
||||
//
|
||||
// Hook a trace to print something when the response comes back.
|
||||
//
|
||||
Config::Connect ("/Names/app/Rtt", MakeCallback (&PingRtt));
|
||||
|
||||
//
|
||||
// Enable a promiscuous pcap trace to see what is coming and going on our device.
|
||||
//
|
||||
EmuHelper emu;
|
||||
emu.EnablePcap ("emu-ping", device, true);
|
||||
|
||||
//
|
||||
// Now, do the actual emulation.
|
||||
//
|
||||
NS_LOG_INFO ("Run Emulation.");
|
||||
Simulator::Stop (Seconds (5.0));
|
||||
Simulator::Run ();
|
||||
Simulator::Destroy ();
|
||||
NS_LOG_INFO ("Done.");
|
||||
}
|
||||
@@ -1,162 +0,0 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
// Network topology
|
||||
//
|
||||
// Normally, the use case for emulated net devices is in collections of
|
||||
// small simulations that connect to the outside world through specific
|
||||
// interfaces. For example, one could construct a number of virtual
|
||||
// machines and connect them via a host-only network. To use the emulated
|
||||
// net device, you would need to set all of the host-only interfaces in
|
||||
// promiscuous mode and provide an appropriate device name (search for "eth1"
|
||||
// below). One could also use the emulated net device in a testbed situation
|
||||
// where the host on which the simulation is running has a specific interface
|
||||
// of interested. You would also need to set this specific interface into
|
||||
// promiscuous mode and provide an appropriate device name.
|
||||
//
|
||||
// This philosophy carries over to this simple example.
|
||||
//
|
||||
// We don't assume any special configuration and all of the ns-3 emulated net
|
||||
// devices will actually talk to the same underlying OS device. We rely on
|
||||
// the fact that the OS will deliver copies of our packets to the other ns-3
|
||||
// net devices since we operate in promiscuous mode.
|
||||
//
|
||||
// Packets will be sent out over the device, but we use MAC spoofing. The
|
||||
// MAC addresses will be generated using the Organizationally Unique Identifier
|
||||
// (OUI) 00:00:00 as a base. This vendor code is not assigned to any
|
||||
// organization and so should not conflict with any real hardware. We'll use
|
||||
// the first n of these addresses, where n is the number of nodes, in this
|
||||
// simualtion. It is up to you to determine that using these MAC addresses is
|
||||
// okay on your network and won't conflict with anything else (including another
|
||||
// simulation using emu devices) on your network. Once you have made this
|
||||
// determination, you need to put the interface you chose into promiscuous mode.
|
||||
// We don't do it for you since you need to think about it first.
|
||||
//
|
||||
// This simulation uses the real-time simulator and so will consume ten seconds
|
||||
// of real time.
|
||||
//
|
||||
// By default, we create the following topology
|
||||
//
|
||||
// n0 n1 n2 n3
|
||||
// | | | |
|
||||
// -----------------
|
||||
// "eth1"
|
||||
//
|
||||
// - UDP flows from n0 to n1 and back
|
||||
// - DropTail queues
|
||||
// - Tracing of queues and packet receptions to file "udp-echo.tr"
|
||||
// - pcap tracing on all devices
|
||||
//
|
||||
|
||||
#include <fstream>
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/internet-module.h"
|
||||
#include "ns3/applications-module.h"
|
||||
#include "ns3/emu-helper.h"
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("EmulatedUdpEchoExample");
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
std::string deviceName ("eth1");
|
||||
std::string encapMode ("Dix");
|
||||
uint32_t nNodes = 4;
|
||||
|
||||
//
|
||||
// Allow the user to override any of the defaults at run-time, via command-line
|
||||
// arguments
|
||||
//
|
||||
CommandLine cmd;
|
||||
cmd.AddValue ("deviceName", "device name", deviceName);
|
||||
cmd.AddValue ("encapsulationMode", "encapsulation mode of emu device (\"Dix\" [default] or \"Llc\")", encapMode);
|
||||
cmd.AddValue ("nNodes", "number of nodes to create (>= 2)", nNodes);
|
||||
|
||||
cmd.Parse (argc, argv);
|
||||
|
||||
GlobalValue::Bind ("SimulatorImplementationType",
|
||||
StringValue ("ns3::RealtimeSimulatorImpl"));
|
||||
|
||||
//
|
||||
// need at least two nodes
|
||||
//
|
||||
nNodes = nNodes < 2 ? 2 : nNodes;
|
||||
|
||||
//
|
||||
// Explicitly create the nodes required by the topology (shown above).
|
||||
//
|
||||
NS_LOG_INFO ("Create nodes.");
|
||||
NodeContainer n;
|
||||
n.Create (nNodes);
|
||||
|
||||
InternetStackHelper internet;
|
||||
internet.Install (n);
|
||||
|
||||
//
|
||||
// Explicitly create the channels required by the topology (shown above).
|
||||
//
|
||||
NS_LOG_INFO ("Create channels.");
|
||||
EmuHelper emu;
|
||||
emu.SetAttribute ("DeviceName", StringValue (deviceName));
|
||||
emu.SetAttribute ("EncapsulationMode", StringValue (encapMode));
|
||||
|
||||
NetDeviceContainer d = emu.Install (n);
|
||||
|
||||
//
|
||||
// We've got the "hardware" in place. Now we need to add IP addresses.
|
||||
//
|
||||
Ipv4AddressHelper ipv4;
|
||||
NS_LOG_INFO ("Assign IP Addresses.");
|
||||
ipv4.SetBase ("10.1.1.0", "255.255.255.0");
|
||||
Ipv4InterfaceContainer i = ipv4.Assign (d);
|
||||
|
||||
//
|
||||
// Create a UdpEchoServer application on node one.
|
||||
//
|
||||
NS_LOG_INFO ("Create Applications.");
|
||||
UdpEchoServerHelper server (9);
|
||||
ApplicationContainer apps = server.Install (n.Get (1));
|
||||
apps.Start (Seconds (1.0));
|
||||
apps.Stop (Seconds (10.0));
|
||||
|
||||
//
|
||||
// Create a UdpEchoClient application to send UDP datagrams from node zero to node one.
|
||||
//
|
||||
uint32_t packetSize = 1024;
|
||||
uint32_t maxPacketCount = 20;
|
||||
Time interPacketInterval = Seconds (0.1);
|
||||
UdpEchoClientHelper client (i.GetAddress (1), 9);
|
||||
client.SetAttribute ("MaxPackets", UintegerValue (maxPacketCount));
|
||||
client.SetAttribute ("Interval", TimeValue (interPacketInterval));
|
||||
client.SetAttribute ("PacketSize", UintegerValue (packetSize));
|
||||
apps = client.Install (n.Get (0));
|
||||
apps.Start (Seconds (2.0));
|
||||
apps.Stop (Seconds (10.0));
|
||||
|
||||
std::ofstream ascii;
|
||||
ascii.open ("emu-udp-echo.tr");
|
||||
emu.EnablePcapAll ("emu-udp-echo", true);
|
||||
|
||||
//
|
||||
// Now, do the actual simulation.
|
||||
//
|
||||
NS_LOG_INFO ("Run Simulation.");
|
||||
Simulator::Run ();
|
||||
Simulator::Destroy ();
|
||||
NS_LOG_INFO ("Done.");
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
|
||||
|
||||
def build(bld):
|
||||
env = bld.env
|
||||
if env['ENABLE_EMU']:
|
||||
obj = bld.create_ns3_program('emu-udp-echo', ['emu', 'internet', 'applications'])
|
||||
obj.source = 'emu-udp-echo.cc'
|
||||
|
||||
obj = bld.create_ns3_program('emu-ping', ['emu', 'internet', 'applications'])
|
||||
obj.source = 'emu-ping.cc'
|
||||
@@ -1,244 +0,0 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2008 University of Washington
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/object-factory.h"
|
||||
#include "ns3/names.h"
|
||||
#include "ns3/queue.h"
|
||||
#include "ns3/emu-net-device.h"
|
||||
#include "ns3/config.h"
|
||||
#include "ns3/packet.h"
|
||||
|
||||
#include "ns3/trace-helper.h"
|
||||
#include "emu-helper.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("EmuHelper");
|
||||
|
||||
EmuHelper::EmuHelper ()
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
m_queueFactory.SetTypeId ("ns3::DropTailQueue");
|
||||
m_deviceFactory.SetTypeId ("ns3::EmuNetDevice");
|
||||
}
|
||||
|
||||
void
|
||||
EmuHelper::SetQueue (
|
||||
std::string type,
|
||||
std::string n1, const AttributeValue &v1,
|
||||
std::string n2, const AttributeValue &v2,
|
||||
std::string n3, const AttributeValue &v3,
|
||||
std::string n4, const AttributeValue &v4)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
m_queueFactory.SetTypeId (type);
|
||||
m_queueFactory.Set (n1, v1);
|
||||
m_queueFactory.Set (n2, v2);
|
||||
m_queueFactory.Set (n3, v3);
|
||||
m_queueFactory.Set (n4, v4);
|
||||
}
|
||||
|
||||
void
|
||||
EmuHelper::SetAttribute (std::string n1, const AttributeValue &v1)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
m_deviceFactory.Set (n1, v1);
|
||||
}
|
||||
|
||||
void
|
||||
EmuHelper::EnablePcapInternal (std::string prefix, Ptr<NetDevice> nd, bool promiscuous, bool explicitFilename)
|
||||
{
|
||||
//
|
||||
// All of the Pcap enable functions vector through here including the ones
|
||||
// that are wandering through all of devices on perhaps all of the nodes in
|
||||
// the system. We can only deal with devices of type EmuNetDevice.
|
||||
//
|
||||
Ptr<EmuNetDevice> device = nd->GetObject<EmuNetDevice> ();
|
||||
if (device == 0)
|
||||
{
|
||||
NS_LOG_INFO ("EmuHelper::EnablePcapInternal(): Device " << device << " not of type ns3::EmuNetDevice");
|
||||
return;
|
||||
}
|
||||
|
||||
PcapHelper pcapHelper;
|
||||
|
||||
std::string filename;
|
||||
if (explicitFilename)
|
||||
{
|
||||
filename = prefix;
|
||||
}
|
||||
else
|
||||
{
|
||||
filename = pcapHelper.GetFilenameFromDevice (prefix, device);
|
||||
}
|
||||
|
||||
Ptr<PcapFileWrapper> file = pcapHelper.CreateFile (filename, std::ios::out, PcapHelper::DLT_EN10MB);
|
||||
if (promiscuous)
|
||||
{
|
||||
pcapHelper.HookDefaultSink<EmuNetDevice> (device, "PromiscSniffer", file);
|
||||
}
|
||||
else
|
||||
{
|
||||
pcapHelper.HookDefaultSink<EmuNetDevice> (device, "Sniffer", file);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EmuHelper::EnableAsciiInternal (
|
||||
Ptr<OutputStreamWrapper> stream,
|
||||
std::string prefix,
|
||||
Ptr<NetDevice> nd,
|
||||
bool explicitFilename)
|
||||
{
|
||||
//
|
||||
// All of the ascii enable functions vector through here including the ones
|
||||
// that are wandering through all of devices on perhaps all of the nodes in
|
||||
// the system. We can only deal with devices of type EmuNetDevice.
|
||||
//
|
||||
Ptr<EmuNetDevice> device = nd->GetObject<EmuNetDevice> ();
|
||||
if (device == 0)
|
||||
{
|
||||
NS_LOG_INFO ("EmuHelper::EnableAsciiInternal(): Device " << device << " not of type ns3::EmuNetDevice");
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Our default trace sinks are going to use packet printing, so we have to
|
||||
// make sure that is turned on.
|
||||
//
|
||||
Packet::EnablePrinting ();
|
||||
|
||||
//
|
||||
// If we are not provided an OutputStreamWrapper, we are expected to create
|
||||
// one using the usual trace filename conventions and do a Hook*WithoutContext
|
||||
// since there will be one file per context and therefore the context would
|
||||
// be redundant.
|
||||
//
|
||||
if (stream == 0)
|
||||
{
|
||||
//
|
||||
// Set up an output stream object to deal with private ofstream copy
|
||||
// constructor and lifetime issues. Let the helper decide the actual
|
||||
// name of the file given the prefix.
|
||||
//
|
||||
AsciiTraceHelper asciiTraceHelper;
|
||||
|
||||
std::string filename;
|
||||
if (explicitFilename)
|
||||
{
|
||||
filename = prefix;
|
||||
}
|
||||
else
|
||||
{
|
||||
filename = asciiTraceHelper.GetFilenameFromDevice (prefix, device);
|
||||
}
|
||||
|
||||
Ptr<OutputStreamWrapper> theStream = asciiTraceHelper.CreateFileStream (filename);
|
||||
|
||||
//
|
||||
// The MacRx trace source provides our "r" event.
|
||||
//
|
||||
asciiTraceHelper.HookDefaultReceiveSinkWithoutContext<EmuNetDevice> (device, "MacRx", theStream);
|
||||
|
||||
//
|
||||
// The "+", '-', and 'd' events are driven by trace sources actually in the
|
||||
// transmit queue.
|
||||
//
|
||||
Ptr<Queue> queue = device->GetQueue ();
|
||||
asciiTraceHelper.HookDefaultEnqueueSinkWithoutContext<Queue> (queue, "Enqueue", theStream);
|
||||
asciiTraceHelper.HookDefaultDropSinkWithoutContext<Queue> (queue, "Drop", theStream);
|
||||
asciiTraceHelper.HookDefaultDequeueSinkWithoutContext<Queue> (queue, "Dequeue", theStream);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// If we are provided an OutputStreamWrapper, we are expected to use it, and
|
||||
// to providd a context. We are free to come up with our own context if we
|
||||
// want, and use the AsciiTraceHelper Hook*WithContext functions, but for
|
||||
// compatibility and simplicity, we just use Config::Connect and let it deal
|
||||
// with the context.
|
||||
//
|
||||
// Note that we are going to use the default trace sinks provided by the
|
||||
// ascii trace helper. There is actually no AsciiTraceHelper in sight here,
|
||||
// but the default trace sinks are actually publicly available static
|
||||
// functions that are always there waiting for just such a case.
|
||||
//
|
||||
uint32_t nodeid = nd->GetNode ()->GetId ();
|
||||
uint32_t deviceid = nd->GetIfIndex ();
|
||||
std::ostringstream oss;
|
||||
|
||||
oss << "/NodeList/" << nd->GetNode ()->GetId () << "/DeviceList/" << deviceid << "/$ns3::EmuNetDevice/MacRx";
|
||||
Config::Connect (oss.str (), MakeBoundCallback (&AsciiTraceHelper::DefaultReceiveSinkWithContext, stream));
|
||||
|
||||
oss.str ("");
|
||||
oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << "/$ns3::EmuNetDevice/TxQueue/Enqueue";
|
||||
Config::Connect (oss.str (), MakeBoundCallback (&AsciiTraceHelper::DefaultEnqueueSinkWithContext, stream));
|
||||
|
||||
oss.str ("");
|
||||
oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << "/$ns3::EmuNetDevice/TxQueue/Dequeue";
|
||||
Config::Connect (oss.str (), MakeBoundCallback (&AsciiTraceHelper::DefaultDequeueSinkWithContext, stream));
|
||||
|
||||
oss.str ("");
|
||||
oss << "/NodeList/" << nodeid << "/DeviceList/" << deviceid << "/$ns3::EmuNetDevice/TxQueue/Drop";
|
||||
Config::Connect (oss.str (), MakeBoundCallback (&AsciiTraceHelper::DefaultDropSinkWithContext, stream));
|
||||
}
|
||||
|
||||
NetDeviceContainer
|
||||
EmuHelper::Install (Ptr<Node> node) const
|
||||
{
|
||||
return NetDeviceContainer (InstallPriv (node));
|
||||
}
|
||||
|
||||
NetDeviceContainer
|
||||
EmuHelper::Install (std::string nodeName) const
|
||||
{
|
||||
Ptr<Node> node = Names::Find<Node> (nodeName);
|
||||
return NetDeviceContainer (InstallPriv (node));
|
||||
}
|
||||
|
||||
NetDeviceContainer
|
||||
EmuHelper::Install (const NodeContainer &c) const
|
||||
{
|
||||
NetDeviceContainer devs;
|
||||
|
||||
for (NodeContainer::Iterator i = c.Begin (); i != c.End (); i++)
|
||||
{
|
||||
devs.Add (InstallPriv (*i));
|
||||
}
|
||||
|
||||
return devs;
|
||||
}
|
||||
|
||||
Ptr<NetDevice>
|
||||
EmuHelper::InstallPriv (Ptr<Node> node) const
|
||||
{
|
||||
Ptr<EmuNetDevice> device = m_deviceFactory.Create<EmuNetDevice> ();
|
||||
device->SetAddress (Mac48Address::Allocate ());
|
||||
node->AddDevice (device);
|
||||
Ptr<Queue> queue = m_queueFactory.Create<Queue> ();
|
||||
device->SetQueue (queue);
|
||||
|
||||
return device;
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
@@ -1,155 +0,0 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2008 University of Washington
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef EMU_HELPER_H
|
||||
#define EMU_HELPER_H
|
||||
|
||||
#include <string>
|
||||
#include <ostream>
|
||||
|
||||
#include "ns3/attribute.h"
|
||||
#include "ns3/object-factory.h"
|
||||
#include "ns3/net-device-container.h"
|
||||
#include "ns3/node-container.h"
|
||||
#include "ns3/emu-net-device.h"
|
||||
|
||||
#include "ns3/trace-helper.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class Packet;
|
||||
|
||||
/**
|
||||
* \brief build a set of EmuNetDevice objects
|
||||
*
|
||||
* Normally we eschew multiple inheritance, however, the classes
|
||||
* PcapUserHelperForDevice and AsciiTraceUserHelperForDevice are
|
||||
* treated as "mixins". A mixin is a self-contained class that
|
||||
* encapsulates a general attribute or a set of functionality that
|
||||
* may be of interest to many other classes.
|
||||
*/
|
||||
class EmuHelper : public PcapHelperForDevice, public AsciiTraceHelperForDevice
|
||||
{
|
||||
public:
|
||||
/*
|
||||
* Construct an EmuHelper() which is used to make installing and configuring
|
||||
* Emulated Net Devices easier.
|
||||
*/
|
||||
EmuHelper ();
|
||||
|
||||
/**
|
||||
* \param type the type of queue
|
||||
* \param n1 the name of the attribute to set on the queue
|
||||
* \param v1 the value of the attribute to set on the queue
|
||||
* \param n2 the name of the attribute to set on the queue
|
||||
* \param v2 the value of the attribute to set on the queue
|
||||
* \param n3 the name of the attribute to set on the queue
|
||||
* \param v3 the value of the attribute to set on the queue
|
||||
* \param n4 the name of the attribute to set on the queue
|
||||
* \param v4 the value of the attribute to set on the queue
|
||||
*
|
||||
* Set the type of queue to create and associated to each
|
||||
* EmuNetDevice created through EmuHelper::Install.
|
||||
*/
|
||||
void SetQueue (std::string type,
|
||||
std::string n1 = "", const AttributeValue &v1 = EmptyAttributeValue (),
|
||||
std::string n2 = "", const AttributeValue &v2 = EmptyAttributeValue (),
|
||||
std::string n3 = "", const AttributeValue &v3 = EmptyAttributeValue (),
|
||||
std::string n4 = "", const AttributeValue &v4 = EmptyAttributeValue ());
|
||||
|
||||
/**
|
||||
* \param n1 the name of the attribute to set
|
||||
* \param v1 the value of the attribute to set
|
||||
*
|
||||
* Set these attributes on each ns3::EmuNetDevice created
|
||||
* by EmuHelper::Install
|
||||
*/
|
||||
void SetAttribute (std::string n1, const AttributeValue &v1);
|
||||
|
||||
/**
|
||||
* This method creates an ns3::EmuNetDevice with the attributes configured by
|
||||
* EmuHelper::SetDeviceAttribute and then adds the device to the node.
|
||||
*
|
||||
* \param node The node to install the device in
|
||||
* \returns A container holding the added net device.
|
||||
*/
|
||||
NetDeviceContainer Install (Ptr<Node> node) const;
|
||||
|
||||
/**
|
||||
* This method creates an ns3::EmuNetDevice with the attributes configured by
|
||||
* EmuHelper::SetDeviceAttribute and then adds the device to the node.
|
||||
*
|
||||
* \param nodeName The name of the node to install the device in
|
||||
* \returns A container holding the added net device.
|
||||
*/
|
||||
NetDeviceContainer Install (std::string nodeName) const;
|
||||
|
||||
/**
|
||||
* For each Ptr<node> in the provided container this method creates an
|
||||
* ns3::EmuNetDevice (with the attributes configured by
|
||||
* EmuHelper::SetDeviceAttribute); adds the device to the node.
|
||||
*
|
||||
* \param c The NodeContainer holding the nodes to be changed.
|
||||
* \returns A container holding the added net devices.
|
||||
*/
|
||||
NetDeviceContainer Install (const NodeContainer &c) const;
|
||||
|
||||
private:
|
||||
/*
|
||||
* \internal
|
||||
*/
|
||||
Ptr<NetDevice> InstallPriv (Ptr<Node> node) const;
|
||||
|
||||
/**
|
||||
* \brief Enable pcap output the indicated net device.
|
||||
*
|
||||
* NetDevice-specific implementation mechanism for hooking the trace and
|
||||
* writing to the trace file.
|
||||
*
|
||||
* \param prefix Filename prefix to use for pcap files.
|
||||
* \param nd Net device for which you want to enable tracing.
|
||||
* \param promiscuous If true capture all possible packets available at the device.
|
||||
* \param explicitFilename Treat the prefix as an explicit filename if true
|
||||
*/
|
||||
virtual void EnablePcapInternal (std::string prefix, Ptr<NetDevice> nd, bool promiscuous, bool explicitFilename);
|
||||
|
||||
/**
|
||||
* \brief Enable ascii trace output on the indicated net device.
|
||||
* \internal
|
||||
*
|
||||
* NetDevice-specific implementation mechanism for hooking the trace and
|
||||
* writing to the trace file.
|
||||
*
|
||||
* \param stream The output stream object to use when logging ascii traces.
|
||||
* \param prefix Filename prefix to use for ascii trace files.
|
||||
* \param nd Net device for which you want to enable tracing.
|
||||
* \param explicitFilename Treat the prefix as an explicit filename if true
|
||||
*/
|
||||
virtual void EnableAsciiInternal (Ptr<OutputStreamWrapper> stream,
|
||||
std::string prefix,
|
||||
Ptr<NetDevice> nd,
|
||||
bool explicitFilename);
|
||||
|
||||
ObjectFactory m_queueFactory;
|
||||
ObjectFactory m_deviceFactory;
|
||||
};
|
||||
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif /* EMU_HELPER_H */
|
||||
@@ -1,111 +0,0 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) University of Washington
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
/**
|
||||
* \brief Convert a byte buffer to a string containing a hex representation
|
||||
* of the buffer. Make the string pretty by adding a colon (':') between
|
||||
* the hex.
|
||||
*
|
||||
* \param buffer The input buffer to be converted.
|
||||
* \param len The length of the input buffer.
|
||||
* \returns A string containing a hex representation of the data in buffer.
|
||||
*/
|
||||
std::string
|
||||
EmuBufferToString (uint8_t *buffer, uint32_t len)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
//
|
||||
// Tell the stream to make hex characters, zero-filled
|
||||
//
|
||||
oss.setf (std::ios::hex, std::ios::basefield);
|
||||
oss.fill ('0');
|
||||
|
||||
//
|
||||
// Loop through the buffer, separating the two-digit-wide hex bytes
|
||||
// with a colon.
|
||||
//
|
||||
for (uint8_t i = 0; i < len; i++)
|
||||
{
|
||||
oss << ":" << std::setw (2) << (uint32_t)buffer[i];
|
||||
}
|
||||
return oss.str ();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Convert string encoded by the inverse function (EmuBufferToString)
|
||||
* back into a byte buffer.
|
||||
*
|
||||
* \param s The input string.
|
||||
* \param buffer The buffer to initialize with the converted bits.
|
||||
* \param len The length of the data that is valid in the buffer.
|
||||
* \returns True indicates a successful conversion.
|
||||
*/
|
||||
bool
|
||||
EmuStringToBuffer (std::string s, uint8_t *buffer, uint32_t *len)
|
||||
{
|
||||
//
|
||||
// If the string was made by our inverse function, the string length must
|
||||
// be a multiple of three characters in length. Use this fact to do a
|
||||
// quick reasonableness test.
|
||||
//
|
||||
if ((s.length () % 3) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::istringstream iss;
|
||||
iss.str (s);
|
||||
|
||||
uint8_t n = 0;
|
||||
|
||||
while (iss.good ())
|
||||
{
|
||||
//
|
||||
// The first character in the "triplet" we're working on is always the
|
||||
// the ':' separator. Read that into a char and make sure we're skipping
|
||||
// what we think we're skipping.
|
||||
//
|
||||
char c;
|
||||
iss.read (&c, 1);
|
||||
if (c != ':')
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// And then read in the real bits and convert them.
|
||||
//
|
||||
uint32_t tmp;
|
||||
iss >> std::hex >> tmp;
|
||||
buffer[n] = tmp;
|
||||
n++;
|
||||
}
|
||||
|
||||
*len = n;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
@@ -1,33 +0,0 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2008 University of Washington
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef EMU_ENCODE_DECODE_H
|
||||
#define EMU_ENCODE_DECODE_H
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
std::string EmuBufferToString (uint8_t *buffer, uint32_t len);
|
||||
bool EmuStringToBuffer (std::string s, uint8_t *buffer, uint32_t *len);
|
||||
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif /* EMU_ENCODE_DECODE_H */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,534 +0,0 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2008 University of Washington
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef EMU_NET_DEVICE_H
|
||||
#define EMU_NET_DEVICE_H
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "ns3/address.h"
|
||||
#include "ns3/net-device.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/callback.h"
|
||||
#include "ns3/packet.h"
|
||||
#include "ns3/traced-callback.h"
|
||||
#include "ns3/event-id.h"
|
||||
#include "ns3/nstime.h"
|
||||
#include "ns3/data-rate.h"
|
||||
#include "ns3/ptr.h"
|
||||
#include "ns3/mac48-address.h"
|
||||
#include "ns3/system-thread.h"
|
||||
#include "ns3/system-mutex.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class Queue;
|
||||
|
||||
/**
|
||||
* \defgroup emu Emu Network Device
|
||||
* This section documents the API of the ns-3 emu module. For a generic functional description, please refer to the ns-3 manual.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \ingroup emu
|
||||
* \class EmuNetDevice
|
||||
* \brief A Device for an Emu Network Link.
|
||||
*/
|
||||
class EmuNetDevice : public NetDevice
|
||||
{
|
||||
public:
|
||||
static TypeId GetTypeId (void);
|
||||
|
||||
/**
|
||||
* Enumeration of the types of packets supported in the class.
|
||||
*/
|
||||
enum EncapsulationMode {
|
||||
ILLEGAL, /**< Encapsulation mode not set */
|
||||
DIX, /**< DIX II / Ethernet II packet */
|
||||
LLC, /**< 802.2 LLC/SNAP Packet*/
|
||||
};
|
||||
|
||||
/**
|
||||
* Construct a EmuNetDevice
|
||||
*
|
||||
* This is the constructor for the EmuNetDevice. It takes as a
|
||||
*/
|
||||
EmuNetDevice ();
|
||||
|
||||
/**
|
||||
* Destroy a EmuNetDevice
|
||||
*
|
||||
* This is the destructor for the EmuNetDevice.
|
||||
*/
|
||||
virtual ~EmuNetDevice ();
|
||||
|
||||
/**
|
||||
* Set the Data Rate used for transmission of packets.
|
||||
*
|
||||
* @see Attach ()
|
||||
* @param bps the data rate at which this object operates
|
||||
*/
|
||||
void SetDataRate (DataRate bps);
|
||||
|
||||
/**
|
||||
* Set a start time for the device.
|
||||
*
|
||||
* @param tStart the start time
|
||||
*/
|
||||
void Start (Time tStart);
|
||||
|
||||
/**
|
||||
* Set a stop time for the device.
|
||||
*
|
||||
* @param tStop the stop time
|
||||
*/
|
||||
void Stop (Time tStop);
|
||||
|
||||
/**
|
||||
* Attach a queue to the EmuNetDevice.
|
||||
*
|
||||
* The EmuNetDevice "owns" a queue that implements a queueing
|
||||
* method such as DropTail or RED.
|
||||
*
|
||||
* @see Queue
|
||||
* @see DropTailQueue
|
||||
* @param queue Ptr to the new queue.
|
||||
*/
|
||||
void SetQueue (Ptr<Queue> queue);
|
||||
|
||||
/**
|
||||
* Get a copy of the attached Queue.
|
||||
*
|
||||
* @returns Ptr to the queue.
|
||||
*/
|
||||
Ptr<Queue> GetQueue (void) const;
|
||||
|
||||
|
||||
//
|
||||
// Pure virtual methods inherited from NetDevice we must implement.
|
||||
//
|
||||
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;
|
||||
|
||||
/**
|
||||
* \brief Make and return a MAC multicast address using the provided
|
||||
* multicast group
|
||||
*
|
||||
* \RFC{1112} says that an Ipv4 host group address is mapped to an Ethernet
|
||||
* multicast address by placing the low-order 23-bits of the IP address into
|
||||
* the low-order 23 bits of the Ethernet multicast address
|
||||
* 01-00-5E-00-00-00 (hex).
|
||||
*
|
||||
* This method performs the multicast address creation function appropriate
|
||||
* to an EUI-48-based CSMA device. This MAC address is encapsulated in an
|
||||
* abstract Address to avoid dependencies on the exact address format.
|
||||
*
|
||||
* \param multicastGroup The IP address for the multicast group destination
|
||||
* of the packet.
|
||||
* \return The MAC multicast Address used to send packets to the provided
|
||||
* multicast group.
|
||||
*
|
||||
* \see Ipv4Address
|
||||
* \see Mac48Address
|
||||
* \see Address
|
||||
*/
|
||||
virtual Address GetMulticast (Ipv4Address multicastGroup) const;
|
||||
|
||||
/**
|
||||
* \brief Get the MAC multicast address corresponding
|
||||
* to the IPv6 address provided.
|
||||
* \param addr IPv6 address
|
||||
* \return the MAC multicast address
|
||||
* \warning Calling this method is invalid if IsMulticast returns not true.
|
||||
*/
|
||||
virtual Address GetMulticast (Ipv6Address addr) const;
|
||||
|
||||
/**
|
||||
* Is this a point to point link?
|
||||
* \returns false.
|
||||
*/
|
||||
virtual bool IsPointToPoint (void) const;
|
||||
|
||||
/**
|
||||
* Is this a bridge?
|
||||
* \returns false.
|
||||
*/
|
||||
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;
|
||||
|
||||
/**
|
||||
* Set the encapsulation mode of this device.
|
||||
*
|
||||
* \param mode The encapsulation mode of this device.
|
||||
*
|
||||
* \see SetFrameSize
|
||||
*/
|
||||
void SetEncapsulationMode (EmuNetDevice::EncapsulationMode mode);
|
||||
|
||||
/**
|
||||
* Get the encapsulation mode of this device.
|
||||
*
|
||||
* \returns The encapsulation mode of this device.
|
||||
*/
|
||||
EmuNetDevice::EncapsulationMode GetEncapsulationMode (void) const;
|
||||
|
||||
private:
|
||||
EmuNetDevice (const EmuNetDevice &);
|
||||
EmuNetDevice & operator= (const EmuNetDevice &);
|
||||
|
||||
virtual void DoDispose (void);
|
||||
|
||||
/**
|
||||
* Call out to a separate process running as suid root in order to get a raw
|
||||
* socket. We do this to avoid having the entire simulation running as root.
|
||||
* If this method returns, we'll have a raw socket waiting for us in m_sock.
|
||||
*/
|
||||
void CreateSocket (void);
|
||||
|
||||
/**
|
||||
* Figure out where the raw socket creation process lives on the system.
|
||||
*/
|
||||
std::string FindCreator (std::string creatorName);
|
||||
|
||||
/**
|
||||
* Spin up the device
|
||||
*/
|
||||
void StartDevice (void);
|
||||
|
||||
/**
|
||||
* Tear down the device
|
||||
*/
|
||||
void StopDevice (void);
|
||||
|
||||
/**
|
||||
* Loop to read and process packets
|
||||
*/
|
||||
void ReadThread (void);
|
||||
|
||||
/**
|
||||
* Method to handle received packets. Synchronized with simulator via ScheduleNow from ReadThread.
|
||||
*/
|
||||
void ForwardUp (uint8_t *buf, uint32_t len);
|
||||
|
||||
/**
|
||||
* Adds the necessary headers and trailers to a packet of data in order to
|
||||
* respect the protocol implemented by the agent.
|
||||
* \param p packet
|
||||
* \param protocolNumber protocol number
|
||||
*/
|
||||
void AddHeader (Ptr<Packet> p, uint16_t protocolNumber);
|
||||
|
||||
/**
|
||||
* Removes, from a packet of data, all headers and trailers that
|
||||
* relate to the protocol implemented by the agent
|
||||
* \param p Packet whose headers need to be processed
|
||||
* \param param An integer parameter that can be set by the function
|
||||
* \return Returns true if the packet should be forwarded up the
|
||||
* protocol stack.
|
||||
*/
|
||||
bool ProcessHeader (Ptr<Packet> p, uint16_t& param);
|
||||
|
||||
/**
|
||||
* Start Sending a Packet Down the Wire.
|
||||
* @param p packet to send
|
||||
* @returns true if success, false on failure
|
||||
*/
|
||||
bool TransmitStart (Ptr<Packet> p);
|
||||
|
||||
void NotifyLinkUp (void);
|
||||
|
||||
/**
|
||||
* The Queue which this EmuNetDevice uses as a packet source.
|
||||
* Management of this Queue has been delegated to the EmuNetDevice
|
||||
* and it has the responsibility for deletion.
|
||||
* @see class Queue
|
||||
* @see class DropTailQueue
|
||||
*/
|
||||
Ptr<Queue> m_queue;
|
||||
|
||||
/**
|
||||
* The trace source fired when packets come into the "top" of the device
|
||||
* at the L3/L2 transition, before being queued for transmission.
|
||||
*
|
||||
* \see class CallBackTraceSource
|
||||
*/
|
||||
TracedCallback<Ptr<const Packet> > m_macTxTrace;
|
||||
|
||||
/**
|
||||
* The trace source fired when packets coming into the "top" of the device
|
||||
* at the L3/L2 transition are dropped before being queued for transmission.
|
||||
*
|
||||
* \see class CallBackTraceSource
|
||||
*/
|
||||
TracedCallback<Ptr<const Packet> > m_macTxDropTrace;
|
||||
|
||||
/**
|
||||
* The trace source fired for packets successfully received by the device
|
||||
* immediately before being forwarded up to higher layers (at the L2/L3
|
||||
* transition). This is a promiscuous trace.
|
||||
*
|
||||
* \see class CallBackTraceSource
|
||||
*/
|
||||
TracedCallback<Ptr<const Packet> > m_macPromiscRxTrace;
|
||||
|
||||
/**
|
||||
* The trace source fired for packets successfully received by the device
|
||||
* immediately before being forwarded up to higher layers (at the L2/L3
|
||||
* transition). This is a non-promiscuous trace.
|
||||
*
|
||||
* \see class CallBackTraceSource
|
||||
*/
|
||||
TracedCallback<Ptr<const Packet> > m_macRxTrace;
|
||||
|
||||
/**
|
||||
* The trace source fired for packets successfully received by the device
|
||||
* but which are dropped before being forwarded up to higher layers (at the
|
||||
* L2/L3 transition).
|
||||
*
|
||||
* \see class CallBackTraceSource
|
||||
*/
|
||||
TracedCallback<Ptr<const Packet> > m_macRxDropTrace;
|
||||
|
||||
/**
|
||||
* The trace source fired when a packet begins the transmission process on
|
||||
* the medium.
|
||||
*
|
||||
* \see class CallBackTraceSource
|
||||
*/
|
||||
TracedCallback<Ptr<const Packet> > m_phyTxBeginTrace;
|
||||
|
||||
/**
|
||||
* The trace source fired when a packet ends the transmission process on
|
||||
* the medium.
|
||||
*
|
||||
* \see class CallBackTraceSource
|
||||
*/
|
||||
TracedCallback<Ptr<const Packet> > m_phyTxEndTrace;
|
||||
|
||||
/**
|
||||
* The trace source fired when the phy layer drops a packet as it tries
|
||||
* to transmit it.
|
||||
*
|
||||
* \see class CallBackTraceSource
|
||||
*/
|
||||
TracedCallback<Ptr<const Packet> > m_phyTxDropTrace;
|
||||
|
||||
/**
|
||||
* The trace source fired when a packet ends the reception process from
|
||||
* the medium.
|
||||
*
|
||||
* \see class CallBackTraceSource
|
||||
*/
|
||||
TracedCallback<Ptr<const Packet> > m_phyRxTrace;
|
||||
|
||||
/**
|
||||
* The trace source fired when a packet begins the reception process from
|
||||
* the medium.
|
||||
*
|
||||
* \see class CallBackTraceSource
|
||||
*/
|
||||
TracedCallback<Ptr<const Packet> > m_phyRxBeginTrace;
|
||||
|
||||
/**
|
||||
* The trace source fired when a packet begins the reception process from
|
||||
* the medium.
|
||||
*
|
||||
* \see class CallBackTraceSource
|
||||
*/
|
||||
TracedCallback<Ptr<const Packet> > m_phyRxEndTrace;
|
||||
|
||||
/**
|
||||
* The trace source fired when the phy layer drops a packet it has received.
|
||||
*
|
||||
* \see class CallBackTraceSource
|
||||
*/
|
||||
TracedCallback<Ptr<const Packet> > m_phyRxDropTrace;
|
||||
|
||||
/**
|
||||
* A trace source that emulates a non-promiscuous protocol sniffer connected
|
||||
* to the device. Unlike your average everyday sniffer, this trace source
|
||||
* will not fire on PACKET_OTHERHOST events.
|
||||
*
|
||||
* On the transmit size, this trace hook will fire after a packet is dequeued
|
||||
* from the device queue for transmission. In Linux, for example, this would
|
||||
* correspond to the point just before a device hard_start_xmit where
|
||||
* dev_queue_xmit_nit is called to dispatch the packet to the PF_PACKET
|
||||
* ETH_P_ALL handlers.
|
||||
*
|
||||
* On the receive side, this trace hook will fire when a packet is received,
|
||||
* just before the receive callback is executed. In Linux, for example,
|
||||
* this would correspond to the point at which the packet is dispatched to
|
||||
* packet sniffers in netif_receive_skb.
|
||||
*
|
||||
* \see class CallBackTraceSource
|
||||
*/
|
||||
TracedCallback<Ptr<const Packet> > m_snifferTrace;
|
||||
|
||||
/**
|
||||
* A trace source that emulates a promiscuous mode protocol sniffer connected
|
||||
* to the device. This trace source fire on packets destined for any host
|
||||
* just like your average everyday packet sniffer.
|
||||
*
|
||||
* On the transmit size, this trace hook will fire after a packet is dequeued
|
||||
* from the device queue for transmission. In Linux, for example, this would
|
||||
* correspond to the point just before a device hard_start_xmit where
|
||||
* dev_queue_xmit_nit is called to dispatch the packet to the PF_PACKET
|
||||
* ETH_P_ALL handlers.
|
||||
*
|
||||
* On the receive side, this trace hook will fire when a packet is received,
|
||||
* just before the receive callback is executed. In Linux, for example,
|
||||
* this would correspond to the point at which the packet is dispatched to
|
||||
* packet sniffers in netif_receive_skb.
|
||||
*
|
||||
* \see class CallBackTraceSource
|
||||
*/
|
||||
TracedCallback<Ptr<const Packet> > m_promiscSnifferTrace;
|
||||
|
||||
/**
|
||||
* Time to start spinning up the device
|
||||
*/
|
||||
Time m_tStart;
|
||||
|
||||
/**
|
||||
* Time to start tearing down the device
|
||||
*/
|
||||
Time m_tStop;
|
||||
|
||||
EventId m_startEvent;
|
||||
EventId m_stopEvent;
|
||||
|
||||
int32_t m_sock;
|
||||
|
||||
Ptr<SystemThread> m_readThread;
|
||||
|
||||
/**
|
||||
* The Node to which this device is attached.
|
||||
*/
|
||||
Ptr<Node> m_node;
|
||||
|
||||
/**
|
||||
* The MAC address which has been assigned to this device.
|
||||
*/
|
||||
Mac48Address m_address;
|
||||
|
||||
/**
|
||||
* The callback used to notify higher layers that a packet has been received.
|
||||
*/
|
||||
NetDevice::ReceiveCallback m_rxCallback;
|
||||
|
||||
/**
|
||||
* The callback used to notify higher layers that a packet has been received in promiscuous mode.
|
||||
*/
|
||||
NetDevice::PromiscReceiveCallback m_promiscRxCallback;
|
||||
|
||||
/**
|
||||
* The ns-3 interface index (in the sense of net device index) that has been assigned to this network device.
|
||||
*/
|
||||
uint32_t m_ifIndex;
|
||||
|
||||
/**
|
||||
* The Unix interface index that we got from the system and which corresponds to the interface (e.g., "eth1")
|
||||
* we are using to talk to the network. Valid when m_sock is valid.
|
||||
*/
|
||||
int32_t m_sll_ifindex;
|
||||
|
||||
/**
|
||||
* The type of packet that should be created by the AddHeader
|
||||
* function and that should be processed by the ProcessHeader
|
||||
* function.
|
||||
*/
|
||||
EncapsulationMode m_encapMode;
|
||||
|
||||
/**
|
||||
* Flag indicating whether or not the link is up. In this case,
|
||||
* whether or not the device is connected to a channel.
|
||||
*/
|
||||
bool m_linkUp;
|
||||
|
||||
/**
|
||||
* Flag indicating whether or not the underlying net device supports
|
||||
* broadcast.
|
||||
*/
|
||||
bool m_isBroadcast;
|
||||
|
||||
/**
|
||||
* Flag indicating whether or not the underlying net device supports
|
||||
* multicast.
|
||||
*/
|
||||
bool m_isMulticast;
|
||||
|
||||
/**
|
||||
* Callbacks to fire if the link changes state (up or down).
|
||||
*/
|
||||
TracedCallback<> m_linkChangeCallbacks;
|
||||
|
||||
/**
|
||||
* The unix/linux name of the underlying device (e.g., eth0)
|
||||
*/
|
||||
std::string m_deviceName;
|
||||
|
||||
/**
|
||||
* A 64K buffer to hold packet data while it is being sent.
|
||||
*/
|
||||
uint8_t *m_packetBuffer;
|
||||
|
||||
/*
|
||||
* a copy of the node id so the read thread doesn't have to GetNode() in
|
||||
* in order to find the node ID. Thread unsafe reference counting in
|
||||
* multithreaded apps is not a good thing.
|
||||
*/
|
||||
uint32_t m_nodeId;
|
||||
|
||||
uint32_t m_maxPendingReads;
|
||||
uint32_t m_pendingReadCount;
|
||||
SystemMutex m_pendingReadMutex;
|
||||
};
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif /* EMU_NET_DEVICE_H */
|
||||
@@ -1,247 +0,0 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) University of Washington
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <cstdlib>
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netpacket/packet.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "emu-encode-decode.h"
|
||||
|
||||
#define EMU_MAGIC 65867
|
||||
|
||||
static int gVerbose = 0;
|
||||
|
||||
#define LOG(msg) \
|
||||
if (gVerbose) \
|
||||
{ \
|
||||
std::cout << __FUNCTION__ << "(): " << msg << std::endl; \
|
||||
}
|
||||
|
||||
#define ABORT(msg, printErrno) \
|
||||
std::cout << __FILE__ << ": fatal error at line " << __LINE__ << ": " << __FUNCTION__ << "(): " << msg << std::endl; \
|
||||
if (printErrno) \
|
||||
{ \
|
||||
std::cout << " errno = " << errno << " (" << std::strerror (errno) << ")" << std::endl; \
|
||||
} \
|
||||
exit (-1);
|
||||
|
||||
#define ABORT_IF(cond, msg, printErrno) \
|
||||
if (cond) \
|
||||
{ \
|
||||
ABORT (msg, printErrno); \
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Send the socket file descriptor we created back to the emu device,
|
||||
* which will read it as soon as we're done.
|
||||
*
|
||||
* \param path The socket address information from the Unix socket we use
|
||||
* to send the created socket back to.
|
||||
* \param fd The socket we're going to send.
|
||||
*/
|
||||
static void
|
||||
SendSocket (const char *path, int fd)
|
||||
{
|
||||
//
|
||||
// Open a Unix (local interprocess) socket to call back to the emu net
|
||||
// device.
|
||||
//
|
||||
LOG ("Create Unix socket");
|
||||
int sock = socket (PF_UNIX, SOCK_DGRAM, 0);
|
||||
ABORT_IF (sock == -1, "Unable to open socket", 1);
|
||||
|
||||
//
|
||||
// We have this string called path, which is really a hex representation
|
||||
// of the endpoint that the net device created. It used a forward encoding
|
||||
// method (EmuBufferToString) to take the sockaddr_un it made and passed
|
||||
// the resulting string to us. So we need to take the inverse method
|
||||
// (EmuStringToBuffer) and build the same sockaddr_un over here.
|
||||
//
|
||||
socklen_t clientAddrLen;
|
||||
struct sockaddr_un clientAddr;
|
||||
|
||||
LOG ("Decode address " << path);
|
||||
bool rc = ns3::EmuStringToBuffer (path, (uint8_t *)&clientAddr, &clientAddrLen);
|
||||
ABORT_IF (rc == false, "Unable to decode path", 0);
|
||||
|
||||
LOG ("Connect");
|
||||
int status = connect (sock, (struct sockaddr*)&clientAddr, clientAddrLen);
|
||||
ABORT_IF (status == -1, "Unable to connect to emu device", 1);
|
||||
|
||||
LOG ("Connected");
|
||||
|
||||
//
|
||||
// This is arcane enough that a few words are worthwhile to explain what's
|
||||
// going on here.
|
||||
//
|
||||
// The interesting information (the socket FD) is going to go back to the
|
||||
// emu net device as an integer of ancillary data. Ancillary data is bits
|
||||
// that are not a part a socket payload (out-of-band data). We're also
|
||||
// going to send one integer back. It's just initialized to a magic number
|
||||
// we use to make sure that the emu device is talking to the emu socket
|
||||
// creator and not some other creator process.
|
||||
//
|
||||
// The struct iovec below is part of a scatter-gather list. It describes a
|
||||
// buffer. In this case, it describes a buffer (an integer) containing the
|
||||
// data that we're going to send back to the emu net device (that magic
|
||||
// number).
|
||||
//
|
||||
struct iovec iov;
|
||||
uint32_t magic = EMU_MAGIC;
|
||||
iov.iov_base = &magic;
|
||||
iov.iov_len = sizeof(magic);
|
||||
|
||||
//
|
||||
// The CMSG macros you'll see below are used to create and access control
|
||||
// messages (which is another name for ancillary data). The ancillary
|
||||
// data is made up of pairs of struct cmsghdr structures and associated
|
||||
// data arrays.
|
||||
//
|
||||
// First, we're going to allocate a buffer on the stack to contain our
|
||||
// data array (that contains the socket). Sometimes you'll see this called
|
||||
// an "ancillary element" but the msghdr uses the control message termimology
|
||||
// so we call it "control."
|
||||
//
|
||||
size_t msg_size = sizeof(int);
|
||||
char control[CMSG_SPACE (msg_size)];
|
||||
|
||||
//
|
||||
// There is a msghdr that is used to minimize the number of parameters
|
||||
// passed to sendmsg (which we will use to send our ancillary data). This
|
||||
// structure uses terminology corresponding to control messages, so you'll
|
||||
// see msg_control, which is the pointer to the ancillary data and controllen
|
||||
// which is the size of the ancillary data array.
|
||||
//
|
||||
// So, initialize the message header that describes our ancillary/control data
|
||||
// and point it to the control message/ancillary data we just allocated space
|
||||
// for.
|
||||
//
|
||||
struct msghdr msg;
|
||||
msg.msg_name = 0;
|
||||
msg.msg_namelen = 0;
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_control = control;
|
||||
msg.msg_controllen = sizeof (control);
|
||||
msg.msg_flags = 0;
|
||||
|
||||
//
|
||||
// A cmsghdr contains a length field that is the length of the header and
|
||||
// the data. It has a cmsg_level field corresponding to the originating
|
||||
// protocol. This takes values which are legal levels for getsockopt and
|
||||
// setsockopt (here SOL_SOCKET). We're going to use the SCM_RIGHTS type of
|
||||
// cmsg, that indicates that the ancillary data array contains access rights
|
||||
// that we are sending back to the emu net device.
|
||||
//
|
||||
// We have to put together the first (and only) cmsghdr that will describe
|
||||
// the whole package we're sending.
|
||||
//
|
||||
struct cmsghdr *cmsg;
|
||||
cmsg = CMSG_FIRSTHDR (&msg);
|
||||
cmsg->cmsg_level = SOL_SOCKET;
|
||||
cmsg->cmsg_type = SCM_RIGHTS;
|
||||
cmsg->cmsg_len = CMSG_LEN (msg_size);
|
||||
//
|
||||
// We also have to update the controllen in case other stuff is actually
|
||||
// in there we may not be aware of (due to macros).
|
||||
//
|
||||
msg.msg_controllen = cmsg->cmsg_len;
|
||||
|
||||
//
|
||||
// Finally, we get a pointer to the start of the ancillary data array and
|
||||
// put our file descriptor in.
|
||||
//
|
||||
int *fdptr = (int*)(CMSG_DATA (cmsg));
|
||||
*fdptr = fd; //
|
||||
|
||||
//
|
||||
// Actually send the file descriptor back to the emulated net device.
|
||||
//
|
||||
ssize_t len = sendmsg (sock, &msg, 0);
|
||||
ABORT_IF (len == -1, "Could not send socket back to emu net device", 1);
|
||||
|
||||
LOG ("sendmsg complete");
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
int c;
|
||||
char *path = NULL;
|
||||
|
||||
opterr = 0;
|
||||
|
||||
while ((c = getopt (argc, argv, "vp:")) != -1)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case 'v':
|
||||
gVerbose = true;
|
||||
break;
|
||||
case 'p':
|
||||
path = optarg;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// This program is spawned by an emu net device running in a simulation. It
|
||||
// wants to create a raw socket as described below. We are going to do the
|
||||
// work here since we're running suid root. Once we create the raw socket,
|
||||
// we have to send it back to the emu net device. We do that over a Unix
|
||||
// (local interprocess) socket. The emu net device created a socket to
|
||||
// listen for our response on, and it is expected to have encoded the address
|
||||
// information as a string and to have passed that string as an argument to
|
||||
// us. We see it here as the "path" string. We can't do anything useful
|
||||
// unless we have that string.
|
||||
//
|
||||
ABORT_IF (path == NULL, "path is a required argument", 0);
|
||||
LOG ("Provided path is \"" << path << "\"");
|
||||
//
|
||||
// The whole reason for all of the hoops we went through to call out to this
|
||||
// program will pay off here. We created this program to run as suid root
|
||||
// in order to keep the main simulation program from having to be run with
|
||||
// root privileges. We need root privileges to be able to open a raw socket
|
||||
// though. So all of these hoops are to allow us to exeucte the following
|
||||
// single line of code:
|
||||
//
|
||||
LOG ("Creating raw socket");
|
||||
int sock = socket (PF_PACKET, SOCK_RAW, htons (ETH_P_ALL));
|
||||
ABORT_IF (sock == -1, "CreateSocket(): Unable to open raw socket", 1);
|
||||
|
||||
//
|
||||
// Send the socket back to the emu net device so it can go about its business
|
||||
//
|
||||
SendSocket (path, sock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
#! /usr/bin/env python
|
||||
## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
|
||||
|
||||
# A list of C++ examples to run in order to ensure that they remain
|
||||
# buildable and runnable over time. Each tuple in the list contains
|
||||
#
|
||||
# (example_name, do_run, do_valgrind_run).
|
||||
#
|
||||
# See test.py for more information.
|
||||
cpp_examples = [
|
||||
("emu-ping", "False", "True"),
|
||||
("emu-udp-echo", "False", "True"),
|
||||
]
|
||||
|
||||
# A list of Python examples to run in order to ensure that they remain
|
||||
# runnable over time. Each tuple in the list contains
|
||||
#
|
||||
# (example_name, do_run).
|
||||
#
|
||||
# See test.py for more information.
|
||||
python_examples = []
|
||||
@@ -1,57 +0,0 @@
|
||||
## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
|
||||
|
||||
import os.path
|
||||
|
||||
def configure(conf):
|
||||
if conf.env['ENABLE_THREADING']:
|
||||
conf.env['ENABLE_EMU'] = conf.check_nonfatal(header_name='netpacket/packet.h',
|
||||
define_name='HAVE_PACKET_H')
|
||||
conf.report_optional_feature("EmuNetDevice", "Emulated Net Device",
|
||||
conf.env['ENABLE_EMU'],
|
||||
"<netpacket/packet.h> include not detected")
|
||||
else:
|
||||
conf.report_optional_feature("EmuNetDevice", "Emulated Net Device",
|
||||
False,
|
||||
"needs threading support which is not available")
|
||||
|
||||
if conf.env['ENABLE_EMU']:
|
||||
#blddir = conf.bldnode.abspath()
|
||||
blddir = os.path.abspath(os.path.join(conf.bldnode.abspath(), conf.variant))
|
||||
emucreatordir = os.path.abspath(os.path.join(blddir, "src/emu"))
|
||||
conf.env.append_value('NS3_EXECUTABLE_PATH', emucreatordir)
|
||||
else:
|
||||
# Add this module to the list of modules that won't be built
|
||||
# if they are enabled.
|
||||
conf.env['MODULES_NOT_BUILT'].append('emu')
|
||||
|
||||
def build(bld):
|
||||
# Don't do anything for this module if emu's not enabled.
|
||||
if not bld.env['ENABLE_EMU']:
|
||||
return
|
||||
|
||||
module = bld.create_ns3_module('emu', ['network'])
|
||||
module.source = [
|
||||
'model/emu-net-device.cc',
|
||||
'model/emu-encode-decode.cc',
|
||||
'helper/emu-helper.cc',
|
||||
]
|
||||
|
||||
headers = bld(features='ns3header')
|
||||
headers.module = 'emu'
|
||||
headers.source = [
|
||||
'model/emu-net-device.h',
|
||||
'helper/emu-helper.h',
|
||||
]
|
||||
|
||||
creator = bld.create_suid_program('emu-sock-creator')
|
||||
creator.source = [
|
||||
'model/emu-sock-creator.cc',
|
||||
'model/emu-encode-decode.cc',
|
||||
]
|
||||
|
||||
module.env.append_value("DEFINES", "EMU_SOCK_CREATOR=\"%s\"" % (creator.target,))
|
||||
|
||||
if bld.env['ENABLE_EXAMPLES']:
|
||||
bld.recurse('examples')
|
||||
|
||||
bld.ns3_python_bindings()
|
||||
@@ -250,7 +250,7 @@ The emulation helper permits to transparently integrate a simulated
|
||||
|
||||
This helper replaces the functionality of the ``EmuNetDevice`` found in
|
||||
|ns3| prior to ns-3.17, by bringing this type of device into the common
|
||||
framework of the FdNetDevice. The ``EmuNetDevice`` will be deprecated
|
||||
framework of the FdNetDevice. The ``EmuNetDevice`` was deprecated
|
||||
in favor of this new helper.
|
||||
|
||||
The device is configured to perform
|
||||
@@ -261,7 +261,8 @@ One can use this helper in a testbed situation where the host on
|
||||
which the simulation is running has a specific interface of interest which
|
||||
drives the testbed hardware. You would also need to set this specific interface
|
||||
into promiscuous mode and provide an appropriate device name to the |ns3|
|
||||
simulation.
|
||||
simulation. Additionally, hardware offloading of segmentation and checksums
|
||||
should be disabled.
|
||||
|
||||
The helper only works if the underlying interface is up and in
|
||||
promiscuous mode. Packets will be sent out over the device, but we use MAC
|
||||
|
||||
Reference in New Issue
Block a user