remove deprecated emu module

This commit is contained in:
Tom Henderson
2014-10-06 14:50:49 -07:00
parent d00ccf814c
commit 94cd3d8542
20 changed files with 4 additions and 12508 deletions

View File

@@ -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 \

View File

@@ -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

View File

@@ -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

View File

@@ -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'])

View File

@@ -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.

View File

@@ -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.");
}

View File

@@ -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.");
}

View File

@@ -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'

View File

@@ -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

View File

@@ -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 */

View File

@@ -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

View File

@@ -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

View File

@@ -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 */

View File

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

View File

@@ -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 = []

View File

@@ -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()

View File

@@ -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