Merge fd-net-device into ns-3-dev

This commit is contained in:
alina
2013-03-27 02:14:57 +01:00
parent 80fe6e05ba
commit b3b3fa9e22
34 changed files with 14920 additions and 0 deletions

View File

@@ -0,0 +1,7 @@
callback_classes = [
['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::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty', 'ns3::empty'],
['void', 'unsigned char*', 'long', 'ns3::empty', 'ns3::empty', '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

@@ -0,0 +1,12 @@
import os
def post_register_types(root_module):
enabled_features = os.environ['NS3_ENABLED_FEATURES'].split(',')
if 'FdNetDevice' not in enabled_features:
for clsname in ['FdNetDevice', 'FdNetDeviceHelper', 'FdNetDeviceFdReader',
'EmuFdNetDeviceHelper', 'PlanetLabFdNetDeviceHelper',
'TapFdNetDeviceHelper']:
root_module.classes.remove(root_module['ns3::%s' % clsname])
root_module.enums.remove(root_module['ns3::FdNetDeviceHelper::EncapsulationMode'])

View File

@@ -0,0 +1,81 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2012 University of Washington, 2012 INRIA
*
* 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
//
#include <sys/socket.h>
#include <errno.h>
#include "ns3/core-module.h"
#include "ns3/network-module.h"
#include "ns3/internet-module.h"
#include "ns3/fd-net-device-module.h"
#include "ns3/applications-module.h"
using namespace ns3;
NS_LOG_COMPONENT_DEFINE ("DummyNetworkExample");
int
main (int argc, char *argv[])
{
GlobalValue::Bind ("SimulatorImplementationType", StringValue ("ns3::RealtimeSimulatorImpl"));
GlobalValue::Bind ("ChecksumEnabled", BooleanValue (true));
NodeContainer nodes;
nodes.Create (2);
InternetStackHelper stack;
stack.Install (nodes);
FdNetDeviceHelper fd;
NetDeviceContainer devices = fd.Install (nodes);
int sv[2];
if (socketpair (AF_UNIX, SOCK_DGRAM, 0, sv) < 0)
{
NS_FATAL_ERROR ("Error creating pipe=" << strerror (errno));
}
Ptr<NetDevice> d1 = devices.Get (0);
Ptr<FdNetDevice> device1 = d1->GetObject<FdNetDevice> ();
device1->SetFileDescriptor (sv[0]);
Ptr<NetDevice> d2 = devices.Get (1);
Ptr<FdNetDevice> device2 = d2->GetObject<FdNetDevice> ();
device2->SetFileDescriptor (sv[1]);
Ipv4AddressHelper addresses;
addresses.SetBase ("10.0.0.0", "255.255.255.0");
Ipv4InterfaceContainer interfaces = addresses.Assign (devices);
Ptr<V4Ping> app = CreateObject<V4Ping> ();
app->SetAttribute ("Remote", Ipv4AddressValue (interfaces.GetAddress (0)));
app->SetAttribute ("Verbose", BooleanValue (true));
nodes.Get (1)->AddApplication (app);
app->SetStartTime (Seconds (0.0));
app->SetStopTime (Seconds (4.0));
fd.EnablePcapAll ("dummy-network", false);
Simulator::Stop (Seconds (5.));
Simulator::Run ();
Simulator::Destroy ();
}

View File

@@ -0,0 +1,196 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2012 University of Washington, 2012 INRIA
*
* 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
*
* Author: Alina Quereilhac <alina.quereilhac@inria.fr>
*
*/
// +----------------------+ +-----------------------+
// | client machine | | server machine |
// +----------------------+ +-----------------------+
// | node 0 | | node 1 |
// | +----------------+ | | +----------------+ |
// | | ns-3 TCP | | | | ns-3 TCP | |
// | +----------------+ | | +----------------+ |
// | | 10.1.1.1 | | | | 10.1.1.2 | |
// | +----------------+ | | +----------------+ |
// | | fd-net-device | | | | fd-net-device | |
// | +----------------+ | | +----------------+ |
// | | raw socket | | | | raw socket | |
// | +----------------+ | | +----------------+ |
// | | eth0 | | | | eth0 | |
// +-------+------+-------+ +--------+------+-------+
//
// 10.1.1.11 10.1.1.12
//
// | |
// +----------------------------+
//
// This example is aimed at meassuring the thoughput of the FdNetDevice
// when using the EmuFdNetDeviceHelper. This is achieved by saturating
// the channel with TCP traffic. Then the thoughput can be obtained from
// the generated .pcap files.
//
// To run this example you will need two computers (client & server).
// Steps to run the experiment:
//
// 1 - Connect the 2 computers with an Ethernet cable
// 2 - Set the IP addresses on both Ethernet devices
//
// client machine: $ sudo ip addr add dev eth0 10.1.1.11/24
// server machine: $ sudo ip addr add dev eth0 10.1.1.12/24
//
// 3 - Set both Ethernet devices to promiscuous mode
//
// both machines: $ sudo ip link set eth0 promisc on
//
// 4 - Give root suid to the raw socket creator binary
//
// both machines: $ sudo chown root.root build/src/fd-net-device/ns3-dev-raw-sock-creator
// both machines: $ sudo chmod 4755 build/src/fd-net-device/ns3-dev-raw-sock-creator
//
// 5 - Run the server side:
//
// server machine: $ ./waf --run="fd-emu-onoff --serverMode=1"
//
// 6 - Run the client side:
//
// client machine: $ ./waf --run="fd-emu-onoff"
//
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include "ns3/core-module.h"
#include "ns3/network-module.h"
#include "ns3/internet-module.h"
#include "ns3/applications-module.h"
#include "ns3/config-store-module.h"
#include "ns3/fd-net-device-module.h"
using namespace ns3;
NS_LOG_COMPONENT_DEFINE ("EmuFdNetDeviceSaturationExample");
int
main (int argc, char *argv[])
{
uint16_t sinkPort = 8000;
uint32_t packetSize = 10000; // bytes
std::string dataRate("1000Mb/s");
bool serverMode = false;
std::string deviceName ("eth0");
std::string client ("10.1.1.1");
std::string server ("10.1.1.2");
std::string netmask ("255.255.255.0");
std::string macClient ("00:00:00:00:00:01");
std::string macServer ("00:00:00:00:00:02");
CommandLine cmd;
cmd.AddValue ("deviceName", "Device name", deviceName);
cmd.AddValue ("client", "Local IP address (dotted decimal only please)", client);
cmd.AddValue ("server", "Remote IP address (dotted decimal only please)", server);
cmd.AddValue ("localmask", "Local mask address (dotted decimal only please)", netmask);
cmd.AddValue ("serverMode", "1:true, 0:false, default client", serverMode);
cmd.AddValue ("mac-client", "Mac Address for Server Client : 00:00:00:00:00:01", macClient);
cmd.AddValue ("mac-server", "Mac Address for Server Default : 00:00:00:00:00:02", macServer);
cmd.AddValue ("data-rate", "Data rate defaults to 1000Mb/s", dataRate);
cmd.Parse (argc, argv);
Ipv4Address remoteIp;
Ipv4Address localIp;
Mac48AddressValue localMac;
if (serverMode)
{
remoteIp = Ipv4Address (client.c_str ());
localIp = Ipv4Address (server.c_str ());
localMac = Mac48AddressValue (macServer.c_str ());
}
else
{
remoteIp = Ipv4Address (server.c_str ());
localIp = Ipv4Address (client.c_str ());
localMac = Mac48AddressValue (macClient.c_str ());
}
Ipv4Mask localMask (netmask.c_str ());
GlobalValue::Bind ("SimulatorImplementationType", StringValue ("ns3::RealtimeSimulatorImpl"));
GlobalValue::Bind ("ChecksumEnabled", BooleanValue (true));
NS_LOG_INFO ("Create Node");
Ptr<Node> node = CreateObject<Node> ();
NS_LOG_INFO ("Create Device");
EmuFdNetDeviceHelper emu;
emu.SetDeviceName (deviceName);
NetDeviceContainer devices = emu.Install (node);
Ptr<NetDevice> device = devices.Get (0);
device->SetAttribute ("Address", localMac);
NS_LOG_INFO ("Add Internet Stack");
InternetStackHelper internetStackHelper;
internetStackHelper.SetIpv4StackInstall(true);
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);
if(serverMode)
{
Address sinkLocalAddress (InetSocketAddress (localIp, sinkPort));
PacketSinkHelper sinkHelper ("ns3::TcpSocketFactory", sinkLocalAddress);
ApplicationContainer sinkApp = sinkHelper.Install (node);
sinkApp.Start (Seconds (1.0));
sinkApp.Stop (Seconds (60.0));
emu.EnablePcap ("fd-server", device);
}
else
{
AddressValue remoteAddress (InetSocketAddress (remoteIp, sinkPort));
OnOffHelper onoff ("ns3::TcpSocketFactory", Address ());
onoff.SetAttribute ("Remote", remoteAddress);
onoff.SetAttribute ("OnTime", StringValue ("ns3::ConstantRandomVariable[Constant=1]"));
onoff.SetAttribute ("OffTime", StringValue ("ns3::ConstantRandomVariable[Constant=0]"));
onoff.SetAttribute ("DataRate", DataRateValue (dataRate));
onoff.SetAttribute ("PacketSize", UintegerValue (packetSize));
ApplicationContainer clientApps = onoff.Install (node);
clientApps.Start (Seconds (4.0));
clientApps.Stop (Seconds (58.0));
emu.EnablePcap ("fd-client", device);
}
Simulator::Stop (Seconds (61.0));
Simulator::Run ();
Simulator::Destroy ();
return 0;
}

View File

@@ -0,0 +1,222 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2012 University of Washington, 2012 INRIA
*
* 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/fd-net-device-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 ("wlan0");
std::string remote ("173.194.34.51"); // 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 ("1.2.3.4");
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");
EmuFdNetDeviceHelper emu;
emu.SetDeviceName (deviceName);
NetDeviceContainer devices = emu.Install (node);
Ptr<NetDevice> device = devices.Get (0);
device->SetAttribute ("Address", Mac48AddressValue (Mac48Address::Allocate ()));
//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 ("1.2.3.4");
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));
app->SetAttribute ("Verbose", BooleanValue (true) );
node->AddApplication (app);
app->SetStartTime (Seconds (1.0));
app->SetStopTime (Seconds (21.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.
//
emu.EnablePcap ("emu-ping", device, true);
//
// Now, do the actual emulation.
//
NS_LOG_INFO ("Run Emulation.");
Simulator::Stop (Seconds (22.0));
Simulator::Run ();
Simulator::Destroy ();
NS_LOG_INFO ("Done.");
}

View File

@@ -0,0 +1,166 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2012 University of Washington, 2012 INRIA
*
* 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
// | |
// -------
// "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/fd-net-device-module.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"));
GlobalValue::Bind ("ChecksumEnabled", BooleanValue (true));
//
// 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.");
EmuFdNetDeviceHelper emu;
emu.SetDeviceName (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::Stop (Seconds (12.0));
Simulator::Run ();
Simulator::Destroy ();
NS_LOG_INFO ("Done.");
}

View File

@@ -0,0 +1,213 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2012 University of Washington, 2012 INRIA
*
* 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 and ping
// the simulated node from the host.
//
// ------------------
// | ns-3 simulation |
// | |
// | ------- |
// | | node | |
// | ------- |
// | | fd- | |
// | | net- | |
// | | device| |
// | ------- |
// | | |
// | | |
// ----|-------------
// | --- --- |
// | | | | | |
// | |TAP| |ETH| |
// | | | | | |
// | --- --- |
// | | |
// |PlanteLab | |
// |host | |
// --------------|----
// |
// |
// ---- (Internet) -------
//
// To use this example:
// 1) The ns-3 will create the TAP device for you in the host machine.
// For this you need to provide the network address to allocate IP addresses
// for the TAP/TU device and the ns-3 FdNetDevice.
// 2) Once the experiment is running you can ping the FdNetDevice IP address from
// the host machine.
// 3) For more information on the required configuration to create TAP devices
// on PlanetLab refer to:
// http://minerva.netgroup.uniroma2.it/fairvpn/wiki/TapDevice
//
#include "ns3/abort.h"
#include "ns3/core-module.h"
#include "ns3/internet-module.h"
#include "ns3/network-module.h"
#include "ns3/fd-net-device-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 ("PlanetLabTAPPingExample");
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 with TAP on PlanetLab host");
std::string remote ("173.194.34.51"); // example.com
//
// Make suer network and mask correspond to those assigned to your PlanetLab
// slice, through the tag vsys_vnet x.x.x.x/yy .
// In this case The network should be x.x.x.x and the mask should correspond to
// the prefix yy.
//
std::string network ("1.2.3.4");
std::string mask ("255.255.255.0");
//
// Allow the user to override any of the defaults at run-time, via
// command-line arguments
//
CommandLine cmd;
cmd.AddValue ("remote", "Remote IP address (dotted decimal only please)", remote);
cmd.AddValue ("tapNetwork", "Network address to assign the TAP device IP address (dotted decimal only please). Note that the network address must be that from the vsys_vnet tag which must exist in your PlanetLab slice.", network);
cmd.AddValue ("tapMask", "Network mask for configure the TAP device (dotted decimal only please)", mask);
cmd.Parse (argc, argv);
NS_ABORT_MSG_IF (network == "1.2.3.4", "You must change the local IP address before running this example");
Ipv4Address remoteIp (remote.c_str ());
Ipv4Address tapNetwork (network.c_str ());
Ipv4Mask tapMask (mask.c_str ());
//
// 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 fd device, set 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.
//
Ipv4AddressHelper addresses;
addresses.SetBase (tapNetwork, tapMask);
Ipv4Address tapIp = addresses.NewAddress ();
NS_LOG_INFO ("Create Device");
PlanetLabFdNetDeviceHelper helper;
helper.SetTapIpAddress (tapIp);
helper.SetTapMask (tapMask);
NetDeviceContainer devices = helper.Install (node);
Ptr<NetDevice> device = devices.Get (0);
//
// Add a default internet stack to the node (ARP, IPv4, ICMP, UDP and TCP).
//
NS_LOG_INFO ("Add Internet Stack");
InternetStackHelper internetStackHelper;
internetStackHelper.Install (node);
//
// Add an address to the ns-3 device in the same network than one
// assigned to the TAP.
//
NS_LOG_INFO ("Create IPv4 Interface");
Ptr<Ipv4> ipv4 = node->GetObject<Ipv4> ();
uint32_t interface = ipv4->AddInterface (device);
Ipv4Address devIp = addresses.NewAddress ();
Ipv4InterfaceAddress address = Ipv4InterfaceAddress (devIp, tapMask);
ipv4->AddAddress (interface, address);
ipv4->SetMetric (interface, 1);
ipv4->SetUp (interface);
//
// Add a route to the ns-3 device so it can reach the outside world though the
// TAP.
//
Ipv4StaticRoutingHelper ipv4RoutingHelper;
Ptr<Ipv4StaticRouting> staticRouting = ipv4RoutingHelper.GetStaticRouting (ipv4);
staticRouting->SetDefaultRoute (tapIp, 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));
app->SetAttribute ("Verbose", BooleanValue (true) );
node->AddApplication (app);
app->SetStartTime (Seconds (1.0));
app->SetStopTime (Seconds (21.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.
//
helper.EnablePcap ("fd-planete-ping", device, true);
//
// Now, do the actual emulation.
//
NS_LOG_INFO ("Run Emulation.");
Simulator::Stop (Seconds (22.0));
Simulator::Run ();
Simulator::Destroy ();
NS_LOG_INFO ("Done.");
}

View File

@@ -0,0 +1,216 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2012 University of Washington, 2012 INRIA
*
* 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 and ping
// the simulated node from the host.
//
// ------------------
// | ns-3 simulation |
// | |
// | ------- |
// | | node | |
// | ------- |
// | | fd- | |
// | | net- | |
// | | device| |
// | ------- |
// | | |
// | | |
// ----|-------------
// | --- --- |
// | | | | | |
// | |TAP| |ETH| |
// | | | | | |
// | --- --- |
// | | |
// | host | |
// --------------|----
// |
// |
// ---- (Internet) -------
//
// To use this example:
// 1) The ns-3 will create the TAP device for you in the host machine.
// For this you need to provide the network address to allocate IP addresses
// for the TAP/TU device and the ns-3 FdNetDevice.
//
// 2) Take into consideration that this experiment requires the host to be able to
// forward the traffic generated by the simulation to the Internet.
// So for Linux systems, make sure to configure:
// # echo 1 > /proc/sys/net/ipv4/ip_forward
//
// 3) Once the experiment is running you can ping the FdNetDevice IP address from
// the host machine.
#include "ns3/abort.h"
#include "ns3/core-module.h"
#include "ns3/internet-module.h"
#include "ns3/network-module.h"
#include "ns3/fd-net-device-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 ("TAPPingExample");
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 with TAP");
std::string deviceName ("tap0");
std::string remote ("192.0.43.10"); // example.com
std::string network ("1.2.3.4");
std::string mask ("255.255.255.0");
std::string pi ("no");
//
// 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.AddValue ("tapNetwork", "Network address to assign the TAP device IP address (dotted decimal only please)", network);
cmd.AddValue ("tapMask", "Network mask for configure the TAP device (dotted decimal only please)", mask);
cmd.AddValue ("modePi", "If 'yes' a PI header will be added to the traffic traversing the device(flag IFF_NOPI will be unset).", pi);
cmd.Parse (argc, argv);
NS_ABORT_MSG_IF (network == "1.2.3.4", "You must change the local IP address before running this example");
Ipv4Address remoteIp (remote.c_str ());
Ipv4Address tapNetwork (network.c_str ());
Ipv4Mask tapMask (mask.c_str ());
bool modePi = ( pi == "yes" ? true : false);
//
// 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 fd device, set 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.
//
Ipv4AddressHelper addresses;
addresses.SetBase (tapNetwork, tapMask);
Ipv4Address tapIp = addresses.NewAddress ();
NS_LOG_INFO ("Create Device");
TapFdNetDeviceHelper helper;
helper.SetDeviceName (deviceName);
helper.SetModePi (modePi);
helper.SetTapIpv4Address (tapIp);
helper.SetTapIpv4Mask (tapMask);
NetDeviceContainer devices = helper.Install (node);
Ptr<NetDevice> device = devices.Get (0);
//
// Add a default internet stack to the node (ARP, IPv4, ICMP, UDP and TCP).
//
NS_LOG_INFO ("Add Internet Stack");
InternetStackHelper internetStackHelper;
internetStackHelper.Install (node);
//
// Add an address to the ns-3 device in the same network than one
// assigned to the TAP.
//
NS_LOG_INFO ("Create IPv4 Interface");
Ptr<Ipv4> ipv4 = node->GetObject<Ipv4> ();
uint32_t interface = ipv4->AddInterface (device);
Ipv4Address devIp = addresses.NewAddress ();
Ipv4InterfaceAddress address = Ipv4InterfaceAddress (devIp, tapMask);
ipv4->AddAddress (interface, address);
ipv4->SetMetric (interface, 1);
ipv4->SetUp (interface);
//
// Add a route to the ns-3 device so it can reach the outside world though the
// TAP.
//
Ipv4StaticRoutingHelper ipv4RoutingHelper;
Ptr<Ipv4StaticRouting> staticRouting = ipv4RoutingHelper.GetStaticRouting (ipv4);
staticRouting->SetDefaultRoute (tapIp, 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));
app->SetAttribute ("Verbose", BooleanValue (true) );
node->AddApplication (app);
app->SetStartTime (Seconds (1.0));
app->SetStopTime (Seconds (21.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.
//
helper.EnablePcap ("fd-tap-ping", device, true);
//
// Now, do the actual emulation.
//
NS_LOG_INFO ("Run Emulation.");
Simulator::Stop (Seconds (25.0));
Simulator::Run ();
Simulator::Destroy ();
NS_LOG_INFO ("Done.");
}

View File

@@ -0,0 +1,164 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2012 University of Washington, 2012 INRIA
*
* 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 TAP device in the host machine.
//
// -------------------------------------------------
// | ns-3 simulation |
// | |
// | ------- -------- |
// | | node | | node | |
// | | (r) | | (n) | |
// | | | | | |
// | ------- -------- -------- |
// | | fd- | csma- | | csma- | |
// | | net- | net- | | net- | |
// | | device| device | | device | |
// | ------- -------- -------- |
// | | |____csma channel_____| |
// | | |
// ----|------------------------------------------
// | --- |
// | | | |
// | |TAP| |
// | | | |
// | --- |
// | |
// | host |
// ------------------
//
//
#include <sstream>
#include <string>
#include "ns3/core-module.h"
#include "ns3/internet-module.h"
#include "ns3/csma-module.h"
#include "ns3/applications-module.h"
#include "ns3/fd-net-device-module.h"
using namespace ns3;
NS_LOG_COMPONENT_DEFINE ("TAPPing6Example");
int
main (int argc, char *argv[])
{
NS_LOG_INFO ("Ping6 Emulation Example with TAP");
//
// 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));
//
// Create the two nodes.
//
Ptr<Node> n = CreateObject<Node> ();
Ptr<Node> r = CreateObject<Node> ();
NodeContainer net (n, r);
//
// Install IPv6 stack.
//
InternetStackHelper internetv6;
internetv6.Install (net);
//
// Create CSMA channel.
//
CsmaHelper csma;
csma.SetChannelAttribute ("DataRate", DataRateValue (5000000));
csma.SetChannelAttribute ("Delay", TimeValue (MilliSeconds (2)));
NetDeviceContainer devs = csma.Install (net);
//
// Assign IPv6 addresses.
//
Ipv6AddressHelper ipv6;
ipv6.SetBase (Ipv6Address ("2001:0DB8:1::"), Ipv6Prefix (64));
Ipv6InterfaceContainer i1 = ipv6.Assign (devs);
i1.SetRouter (1, true);
ipv6.SetBase (Ipv6Address ("2001:0DB8:2::"), Ipv6Prefix (64));
Ipv6Address tapAddr = ipv6.NewAddress ();
std::stringstream ss;
std::string tapIp;
tapAddr.Print (ss);
ss >> tapIp;
//
// Create FdNetDevice.
//
TapFdNetDeviceHelper helper;
helper.SetDeviceName ("tap0");
helper.SetTapIpv6Address (tapIp.c_str ());
helper.SetTapIpv6Prefix (64);
NetDeviceContainer fdevs = helper.Install (r);
Ptr<NetDevice> device = fdevs.Get (0);
Ptr<FdNetDevice> fdevice = device->GetObject<FdNetDevice> ();
fdevice-> SetIsMulticast (true);
Ipv6InterfaceContainer i2 = ipv6.Assign (fdevs);
i2.SetRouter (0, true);
//
// Create the Ping6 application.
//
uint32_t packetSize = 1024;
uint32_t maxPacketCount = 1;
Time interPacketInterval = Seconds (1.0);
Ping6Helper ping6;
ping6.SetRemote (tapIp.c_str ());
ping6.SetAttribute ("MaxPackets", UintegerValue (maxPacketCount));
ping6.SetAttribute ("Interval", TimeValue (interPacketInterval));
ping6.SetAttribute ("PacketSize", UintegerValue (packetSize));
ApplicationContainer apps = ping6.Install (n);
apps.Start (Seconds (2.0));
apps.Stop (Seconds (20.0));
AsciiTraceHelper ascii;
csma.EnableAsciiAll (ascii.CreateFileStream ("csma-ping6.tr"));
csma.EnablePcapAll ("csma-ping6", true);
//
// Enable a promiscuous pcap trace to see what is coming and going on in the fd-net-device.
//
helper.EnablePcap ("fd-ping6", fdevice, true);
//
// Run the experiment.
//
NS_LOG_INFO ("Run Emulation.");
Simulator::Stop (Seconds (200.0));
Simulator::Run ();
Simulator::Destroy ();
NS_LOG_INFO ("Done.");
}

View File

@@ -0,0 +1,127 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2012 University of Washington, 2012 INRIA
*
* 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
*
* Author: Alina Quereilhac <alina.quereilhac@inria.fr>
*
*/
//
// node 0 node 1
// +----------------+ +----------------+
// | ns-3 TCP | | ns-3 TCP |
// +----------------+ +----------------+
// | 10.1.1.1 | | 10.1.1.2 |
// +----------------+ socketpair +----------------+
// | fd-net-device |--------------| fd-net-device |
// +----------------+ +----------------+
//
// This example is aimed at meassuring the thoughput of the FdNetDevice
// in a pure simulation. For this purpose two FdNetDevices, attached to
// different nodes but in a same simulation, are connected using a socket pair.
// TCP traffic is sent at a saturating data rate. Then the thoughput can
// be obtained from the generated .pcap files.
//
// Steps to run the experiment:
//
// $ ./waf --run="fd2fd-onoff"
//
#include <sys/socket.h>
#include <errno.h>
#include "ns3/core-module.h"
#include "ns3/network-module.h"
#include "ns3/internet-module.h"
#include "ns3/fd-net-device-module.h"
#include "ns3/applications-module.h"
using namespace ns3;
NS_LOG_COMPONENT_DEFINE ("FdNetDeviceSaturationExample");
int
main (int argc, char *argv[])
{
uint16_t sinkPort = 8000;
uint32_t packetSize = 10000; // bytes
std::string dataRate("1000Mb/s");
GlobalValue::Bind ("SimulatorImplementationType", StringValue ("ns3::RealtimeSimulatorImpl"));
GlobalValue::Bind ("ChecksumEnabled", BooleanValue (true));
NS_LOG_INFO ("Create Node");
NodeContainer nodes;
nodes.Create (2);
NS_LOG_INFO ("Create Device");
FdNetDeviceHelper fd;
NetDeviceContainer devices = fd.Install (nodes);
int sv[2];
if (socketpair (AF_UNIX, SOCK_DGRAM, 0, sv) < 0)
{
NS_FATAL_ERROR ("Error creating pipe=" << strerror (errno));
}
Ptr<NetDevice> d1 = devices.Get (0);
Ptr<FdNetDevice> clientDevice = d1->GetObject<FdNetDevice> ();
clientDevice->SetFileDescriptor (sv[0]);
Ptr<NetDevice> d2 = devices.Get (1);
Ptr<FdNetDevice> serverDevice = d2->GetObject<FdNetDevice> ();
serverDevice->SetFileDescriptor (sv[1]);
NS_LOG_INFO ("Add Internet Stack");
InternetStackHelper internetStackHelper;
internetStackHelper.SetIpv4StackInstall(true);
internetStackHelper.Install (nodes);
NS_LOG_INFO ("Create IPv4 Interface");
Ipv4AddressHelper addresses;
addresses.SetBase ("10.0.0.0", "255.255.255.0");
Ipv4InterfaceContainer interfaces = addresses.Assign (devices);
Ptr<Node> clientNode = nodes.Get (0);
Ipv4Address serverIp = interfaces.GetAddress (1);
Ptr<Node> serverNode = nodes.Get (1);
// server
Address sinkLocalAddress (InetSocketAddress (serverIp, sinkPort));
PacketSinkHelper sinkHelper ("ns3::TcpSocketFactory", sinkLocalAddress);
ApplicationContainer sinkApp = sinkHelper.Install (serverNode);
sinkApp.Start (Seconds (0.0));
sinkApp.Stop (Seconds (40.0));
fd.EnablePcap ("fd-server", serverDevice);
// client
AddressValue serverAddress (InetSocketAddress (serverIp, sinkPort));
OnOffHelper onoff ("ns3::TcpSocketFactory", Address ());
onoff.SetAttribute ("Remote", serverAddress);
onoff.SetAttribute ("OnTime", StringValue ("ns3::ConstantRandomVariable[Constant=1]"));
onoff.SetAttribute ("OffTime", StringValue ("ns3::ConstantRandomVariable[Constant=0]"));
onoff.SetAttribute ("DataRate", DataRateValue (dataRate));
onoff.SetAttribute ("PacketSize", UintegerValue (packetSize));
ApplicationContainer clientApps = onoff.Install (clientNode);
clientApps.Start (Seconds (1.0));
clientApps.Stop (Seconds (39.0));
fd.EnablePcap ("fd-client", clientDevice);
Simulator::Stop (Seconds (40.0));
Simulator::Run ();
Simulator::Destroy ();
}

1
src/fd-net-device/examples/waf vendored Normal file
View File

@@ -0,0 +1 @@
exec "`dirname "$0"`"/../../waf "$@"

View File

@@ -0,0 +1,28 @@
## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
def build(bld):
env = bld.env
if env['ENABLE_FDNETDEV']:
obj = bld.create_ns3_program('dummy-network', ['fd-net-device', 'internet', 'applications'])
obj.source = 'dummy-network.cc'
obj = bld.create_ns3_program('fd2fd-onoff', ['fd-net-device', 'internet', 'applications'])
obj.source = 'fd2fd-onoff.cc'
if bld.env['ENABLE_TAP']:
obj = bld.create_ns3_program('fd-emu-ping', ['fd-net-device', 'internet', 'applications'])
obj.source = 'fd-emu-ping.cc'
obj = bld.create_ns3_program('fd-emu-udp-echo', ['fd-net-device', 'internet', 'applications'])
obj.source = 'fd-emu-udp-echo.cc'
obj = bld.create_ns3_program('fd-emu-onoff', ['fd-net-device', 'internet', 'applications'])
obj.source = 'fd-emu-onoff.cc'
if bld.env['ENABLE_TAP']:
obj = bld.create_ns3_program('fd-tap-ping', ['fd-net-device', 'internet', 'applications'])
obj.source = 'fd-tap-ping.cc'
obj = bld.create_ns3_program('fd-tap-ping6', ['fd-net-device', 'internet', 'applications', 'csma'])
obj.source = 'fd-tap-ping6.cc'
if bld.env['ENABLE_PLANETLAB']:
obj = bld.create_ns3_program('fd-planetlab-ping', ['fd-net-device', 'internet', 'applications'])
obj.source = 'fd-planetlab-ping.cc'

View File

@@ -0,0 +1,176 @@
/* -*- 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 <stdlib.h>
#include <errno.h>
#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 "creator-utils.h"
#include "encode-decode.h"
namespace ns3 {
int gVerbose = 0;
/**
* \brief Send the file descriptor back to the code that invoked the creation.
*
* \param path The socket address information from the Unix socket we use
* to send the created socket back to.
* \param fd The file descriptor we're going to send.
* \param magic_number A verification number to verify the caller is talking to the
* right process.
*/
void
SendSocket (const char *path, int fd, const int magic_number)
{
//
// 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 (BufferToString) to take the sockaddr_un it made and passed
// the resulting string to us. So we need to take the inverse method
// (StringToBuffer) and build the same sockaddr_un over here.
//
socklen_t clientAddrLen;
struct sockaddr_un clientAddr;
LOG ("Decode address " << path);
bool rc = ns3::StringToBuffer (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
// fd 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 fd 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 = magic_number;
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");
}
} // namespace ns3

View File

@@ -0,0 +1,70 @@
/* -*- 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
*/
#ifndef CREATOR_UTILS_H
#define CREATOR_UTILS_H
#include <unistd.h>
#include <string>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <stdlib.h>
#include <errno.h>
#include <sys/socket.h>
namespace ns3 {
extern int gVerbose;
#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 << " (" << strerror (errno) << ")" << std::endl; \
} \
exit (-1);
#define ABORT_IF(cond, msg, printErrno) \
if (cond) \
{ \
ABORT (msg, printErrno); \
}
/**
* \brief Send the file descriptor back to the code that invoked the creation.
*
* \param path The socket address information from the Unix socket we use
* to send the created socket back to.
* \param fd The file descriptor we're going to send.
* \param magic_number A verification number to verify the caller is talking to the
* right process.
*/
void SendSocket (const char *path, int fd, const int magic_number);
} // namespace ns3
#endif /* CREATOR_UTILS_DEVICE_H */

View File

@@ -0,0 +1,419 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2012 INRIA, 2012 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 "emu-fd-net-device-helper.h"
#include "encode-decode.h"
#include "ns3/abort.h"
#include "ns3/config.h"
#include "ns3/fd-net-device.h"
#include "ns3/log.h"
#include "ns3/names.h"
#include "ns3/object-factory.h"
#include "ns3/packet.h"
#include "ns3/simulator.h"
#include "ns3/trace-helper.h"
#include <arpa/inet.h>
#include <errno.h>
#include <iostream>
#include <iomanip>
#include <limits>
#include <linux/if_tun.h>
#include <memory>
#include <net/ethernet.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netpacket/packet.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/ioctl.h>
#include <time.h>
#include <unistd.h>
#include <string>
NS_LOG_COMPONENT_DEFINE ("EmuFdNetDeviceHelper");
namespace ns3 {
#define EMU_MAGIC 65867
EmuFdNetDeviceHelper::EmuFdNetDeviceHelper ()
{
m_deviceName = "undefined";
}
void
EmuFdNetDeviceHelper::SetDeviceName (std::string deviceName)
{
m_deviceName = deviceName;
}
std::string
EmuFdNetDeviceHelper::GetDeviceName (void)
{
return m_deviceName;
}
Ptr<NetDevice>
EmuFdNetDeviceHelper::InstallPriv (Ptr<Node> node) const
{
Ptr<NetDevice> d = FdNetDeviceHelper::InstallPriv (node);
Ptr<FdNetDevice> device = d->GetObject<FdNetDevice> ();
SetFileDescriptor (device);
return device;
}
void
EmuFdNetDeviceHelper::SetFileDescriptor (Ptr<FdNetDevice> device) const
{
NS_LOG_LOGIC ("Creating EMU socket");
if (m_deviceName == "undefined")
{
NS_FATAL_ERROR ("EmuFdNetDeviceHelper::SetFileDescriptor (): m_deviceName is not set");
}
//
// 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.
//
int fd = CreateFileDescriptor ();
device->SetFileDescriptor (fd);
//
// Figure out which interface index corresponds to the device name in the corresponding attribute.
//
struct ifreq ifr;
bzero (&ifr, sizeof(ifr));
strncpy ((char *)ifr.ifr_name, m_deviceName.c_str (), IFNAMSIZ);
NS_LOG_LOGIC ("Getting interface index");
int32_t rc = ioctl (fd, SIOCGIFINDEX, &ifr);
if (rc == -1)
{
NS_FATAL_ERROR ("EmuFdNetDeviceHelper::SetFileDescriptor (): Can't get interface index");
}
//
// Bind the socket to the interface we just found.
//
struct sockaddr_ll ll;
bzero (&ll, sizeof(ll));
ll.sll_family = AF_PACKET;
ll.sll_ifindex = ifr.ifr_ifindex;
ll.sll_protocol = htons (ETH_P_ALL);
NS_LOG_LOGIC ("Binding socket to interface");
rc = bind (fd, (struct sockaddr *)&ll, sizeof (ll));
if (rc == -1)
{
NS_FATAL_ERROR ("EmuFdNetDeviceHelper::SetFileDescriptor (): Can't bind to specified interface");
}
rc = ioctl (fd, SIOCGIFFLAGS, &ifr);
if (rc == -1)
{
NS_FATAL_ERROR ("EmuFdNetDeviceHelper::SetFileDescriptor (): Can't get interface flags");
}
//
// This device only works if the underlying interface is up in promiscuous
// mode. We could have turned it on in the socket creator, but the situation
// is that we expect these devices to be used in conjunction with virtual
// machines with connected host-only (simulated) networks, or in a testbed.
// There is a lot of setup and configuration happening outside of this one
// issue, and we expect that configuration to include choosing a valid
// interface (e.g, "ath1"), ensuring that the device supports promiscuous
// mode, and placing it in promiscuous mode. We just make sure of the
// end result.
//
if ((ifr.ifr_flags & IFF_PROMISC) == 0)
{
NS_FATAL_ERROR ("EmuFdNetDeviceHelper::SetFileDescriptor (): " << m_deviceName.c_str () << " is not in promiscuous mode");
}
if ((ifr.ifr_flags & IFF_BROADCAST) != IFF_BROADCAST)
{
// We default m_isBroadcast to true but turn it off here if not
// supported, because in the common case, overlying IP code will
// assert during configuration time if this is false, before this
// method has a chance to set it during runtime
device->SetIsBroadcast (false);
}
if ((ifr.ifr_flags & IFF_MULTICAST) == IFF_MULTICAST)
{
// This one is OK to enable at runtime
device->SetIsMulticast (true);
}
// Set the MTU of the device to the mtu of the associated network interface
struct ifreq ifr2;
bzero (&ifr2, sizeof (ifr2));
strcpy (ifr2.ifr_name, m_deviceName.c_str ());
int32_t mtufd = socket (PF_INET, SOCK_DGRAM, IPPROTO_IP);
rc = ioctl (mtufd, SIOCGIFMTU, &ifr2);
if (rc == -1)
{
NS_FATAL_ERROR ("FdNetDevice::SetFileDescriptor (): Can't ioctl SIOCGIFMTU");
}
close (mtufd);
device->SetMtu (ifr.ifr_mtu);
}
int
EmuFdNetDeviceHelper::CreateFileDescriptor (void) const
{
NS_LOG_FUNCTION (this);
#ifdef HAVE_RAW_SOCKET_CREATOR
//
// We want to create a raw socket for our net device. Unfortunately for us
// you have to have root privileges to do that. Instead of running the
// entire simulation as root, we decided to make a small program who's whole
// reason for being is to run as suid root and create a raw socket. We're
// going to fork and exec that program soon, but we need to have a socket
// to talk to it with. So we create a local interprocess (Unix) socket
// for that purpose.
//
int sock = socket (PF_UNIX, SOCK_DGRAM, 0);
if (sock == -1)
{
NS_FATAL_ERROR ("EmuFdNetDeviceHelper::CreateFileDescriptor(): Unix socket creation error, errno = " << strerror (errno));
}
//
// Bind to that socket and let the kernel allocate an endpoint
//
struct sockaddr_un un;
memset (&un, 0, sizeof (un));
un.sun_family = AF_UNIX;
int status = bind (sock, (struct sockaddr*)&un, sizeof (sa_family_t));
if (status == -1)
{
NS_FATAL_ERROR ("EmuFdNetDeviceHelper::CreateFileDescriptor(): Could not bind(): errno = " << strerror (errno));
}
NS_LOG_INFO ("Created Unix socket");
NS_LOG_INFO ("sun_family = " << un.sun_family);
NS_LOG_INFO ("sun_path = " << un.sun_path);
//
// We have a socket here, but we want to get it there -- to the program we're
// going to exec. What we'll do is to do a getsockname and then encode the
// resulting address information as a string, and then send the string to the
// program as an argument. So we need to get the sock name.
//
socklen_t len = sizeof (un);
status = getsockname (sock, (struct sockaddr*)&un, &len);
if (status == -1)
{
NS_FATAL_ERROR ("EmuFdNetDeviceHelper::CreateFileDescriptor(): Could not getsockname(): errno = " << strerror (errno));
}
//
// Now encode that socket name (family and path) as a string of hex digits
//
std::string path = BufferToString ((uint8_t *)&un, len);
NS_LOG_INFO ("Encoded Unix socket as \"" << path << "\"");
//
// Fork and exec the process to create our socket. If we're us (the parent)
// we wait for the child (the socket creator) to complete and read the
// socket it created using the ancillary data mechanism.
//
// Tom Goff reports the possiblility of a deadlock when trying to acquire the
// python GIL here. He says that this might be due to trying to access Python
// objects after fork() without calling PyOS_AfterFork() to properly reset
// Python state (including the GIL). There is no code to cause the problem
// here in emu, but this was visible in similar code in tap-bridge.
//
pid_t pid = ::fork ();
if (pid == 0)
{
NS_LOG_DEBUG ("Child process");
//
// build a command line argument from the encoded endpoint string that
// the socket creation process will use to figure out how to respond to
// the (now) parent process.
//
std::ostringstream oss;
oss << "-p" << path;
NS_LOG_INFO ("Parameters set to \"" << oss.str () << "\"");
//
// Execute the socket creation process image.
//
status = ::execlp (RAW_SOCK_CREATOR,
RAW_SOCK_CREATOR, // argv[0] (filename)
oss.str ().c_str (), // argv[1] (-p<path?
(char *)NULL);
//
// If the execlp successfully completes, it never returns. If it returns it failed or the OS is
// broken. In either case, we bail.
//
NS_FATAL_ERROR ("EmuFdNetDeviceHelper::CreateFileDescriptor(): Back from execlp(), errno = " << ::strerror (errno));
}
else
{
NS_LOG_DEBUG ("Parent process");
//
// We're the process running the emu net device. We need to wait for the
// socket creator process to finish its job.
//
int st;
pid_t waited = waitpid (pid, &st, 0);
if (waited == -1)
{
NS_FATAL_ERROR ("EmuFdNetDeviceHelper::CreateFileDescriptor(): waitpid() fails, errno = " << strerror (errno));
}
NS_ASSERT_MSG (pid == waited, "EmuFdNetDeviceHelper::CreateFileDescriptor(): pid mismatch");
//
// Check to see if the socket creator exited normally and then take a
// look at the exit code. If it bailed, so should we. If it didn't
// even exit normally, we bail too.
//
if (WIFEXITED (st))
{
int exitStatus = WEXITSTATUS (st);
if (exitStatus != 0)
{
NS_FATAL_ERROR ("EmuFdNetDeviceHelper::CreateFileDescriptor(): socket creator exited normally with status " << exitStatus);
}
}
else
{
NS_FATAL_ERROR ("EmuFdNetDeviceHelper::CreateFileDescriptor(): socket creator exited abnormally");
}
//
// At this point, the socket creator has run successfully and should
// have created our raw socket and sent it back to the socket address
// we provided. Our socket should be waiting on the Unix socket. We've
// got to do a bunch of grunto work to get at it, though.
//
// The struct iovec below is part of a scatter-gather list. It describes a
// buffer. In this case, it describes a buffer (an integer) that will
// get the data that comes back from the socket creator process. It will
// be a magic number that we use as a consistency/sanity check.
//
struct iovec iov;
uint32_t 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 receive 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 recvmsg (which we will use to receive 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 the ancillary/control
// data we expect to receive and point it to buffer.
//
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;
//
// Now we can actually receive the interesting bits from the socket
// creator process.
//
ssize_t bytesRead = recvmsg (sock, &msg, 0);
if (bytesRead != sizeof(int))
{
NS_FATAL_ERROR ("EmuFdNetDeviceHelper::CreateFileDescriptor(): Wrong byte count from socket creator");
}
//
// There may be a number of message headers/ancillary data arrays coming in.
// Let's look for the one with a type SCM_RIGHTS which indicates it' the
// one we're interested in.
//
struct cmsghdr *cmsg;
for (cmsg = CMSG_FIRSTHDR (&msg); cmsg != NULL; cmsg = CMSG_NXTHDR (&msg, cmsg))
{
if (cmsg->cmsg_level == SOL_SOCKET
&& cmsg->cmsg_type == SCM_RIGHTS)
{
//
// This is the type of message we want. Check to see if the magic
// number is correct and then pull out the socket we care about if
// it matches
//
if (magic == EMU_MAGIC)
{
NS_LOG_INFO ("Got SCM_RIGHTS with correct magic " << magic);
int *rawSocket = (int*)CMSG_DATA (cmsg);
NS_LOG_INFO ("Got the socket from the socket creator = " << *rawSocket);
return *rawSocket;
}
else
{
NS_LOG_INFO ("Got SCM_RIGHTS, but with bad magic " << magic);
}
}
}
NS_FATAL_ERROR ("Did not get the raw socket from the socket creator");
}
#else
NS_FATAL_ERROR ("RAW_SOCKET_CREATOR is not defined in your system.");
#endif /* HAVE_RAW_SOCKET_CREATOR */
}
} // namespace ns3

View File

@@ -0,0 +1,91 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2012 INRIA, 2012 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_FD_NET_DEVICE_HELPER_H
#define EMU_FD_NET_DEVICE_HELPER_H
#include <string>
#include "ns3/attribute.h"
#include "ns3/fd-net-device.h"
#include "ns3/fd-net-device-helper.h"
#include "ns3/object-factory.h"
#include "ns3/net-device-container.h"
#include "ns3/node-container.h"
namespace ns3 {
/**
* \brief build a set of FdNetDevice objects attached to a physical network
* interface
*
*/
class EmuFdNetDeviceHelper : public FdNetDeviceHelper
{
public:
/**
* Construct a EmuFdNetDeviceHelper.
*/
EmuFdNetDeviceHelper ();
virtual ~EmuFdNetDeviceHelper ()
{
}
/**
* Get the device name of this device.
*
* \returns The device name of this device.
*/
std::string GetDeviceName (void);
/**
* Set the device name of this device.
*
* \param deviceName The device name of this device.
*/
void SetDeviceName (std::string deviceName);
protected:
/*
* \internal
*/
Ptr<NetDevice> InstallPriv (Ptr<Node> node) const;
/**
* Sets a file descriptor on the FileDescriptorNetDevice.
*/
virtual void SetFileDescriptor (Ptr<FdNetDevice> device) const;
/**
* 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.
*/
virtual int CreateFileDescriptor (void) const;
/**
* \internal
*
* The unix/linux name of the underlying device (e.g., eth0)
*/
std::string m_deviceName;
};
} // namespace ns3
#endif /* EMU_FD_NET_DEVICE_HELPER_H */

View File

@@ -0,0 +1,111 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2009 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
BufferToString (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 (TapBufferToString)
* 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
StringToBuffer (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

@@ -0,0 +1,33 @@
/* -*- 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 ENCODE_DECODE_H
#define ENCODE_DECODE_H
#include <string>
namespace ns3 {
std::string BufferToString (uint8_t *buffer, uint32_t len);
bool StringToBuffer (std::string s, uint8_t *buffer, uint32_t *len);
} // namespace ns3
#endif /* ENCODE_DECODE_H */

View File

@@ -0,0 +1,204 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2012 INRIA
*
* 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
*
* Author: Alina Quereilhac <alina.quereilhac@inria.fr>
*
*/
#include "fd-net-device-helper.h"
#include "ns3/abort.h"
#include "ns3/config.h"
#include "ns3/fd-net-device.h"
#include "ns3/log.h"
#include "ns3/names.h"
#include "ns3/object-factory.h"
#include "ns3/packet.h"
#include "ns3/simulator.h"
#include "ns3/trace-helper.h"
#include <string>
NS_LOG_COMPONENT_DEFINE ("FdNetDeviceHelper");
namespace ns3 {
FdNetDeviceHelper::FdNetDeviceHelper ()
{
m_deviceFactory.SetTypeId ("ns3::FdNetDevice");
}
void
FdNetDeviceHelper::SetAttribute (std::string n1, const AttributeValue &v1)
{
NS_LOG_FUNCTION (this);
m_deviceFactory.Set (n1, v1);
}
void
FdNetDeviceHelper::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 FdNetDevice.
//
Ptr<FdNetDevice> device = nd->GetObject<FdNetDevice> ();
if (device == 0)
{
NS_LOG_INFO ("FdNetDeviceHelper::EnablePcapInternal(): Device " << device << " not of type ns3::FdNetDevice");
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<FdNetDevice> (device, "PromiscSniffer", file);
}
else
{
pcapHelper.HookDefaultSink<FdNetDevice> (device, "Sniffer", file);
}
}
void
FdNetDeviceHelper::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 FdNetDevice.
//
Ptr<FdNetDevice> device = nd->GetObject<FdNetDevice> ();
if (device == 0)
{
NS_LOG_INFO ("FdNetDeviceHelper::EnableAsciiInternal(): Device " << device << " not of type ns3::FdNetDevice");
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<FdNetDevice> (device, "MacRx", 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 deviceid = nd->GetIfIndex ();
std::ostringstream oss;
oss << "/NodeList/" << nd->GetNode ()->GetId () << "/DeviceList/" << deviceid << "/$ns3::FdNetDevice/MacRx";
Config::Connect (oss.str (), MakeBoundCallback (&AsciiTraceHelper::DefaultReceiveSinkWithContext, stream));
}
NetDeviceContainer
FdNetDeviceHelper::Install (Ptr<Node> node) const
{
return NetDeviceContainer (InstallPriv (node));
}
NetDeviceContainer
FdNetDeviceHelper::Install (std::string nodeName) const
{
Ptr<Node> node = Names::Find<Node> (nodeName);
return NetDeviceContainer (InstallPriv (node));
}
NetDeviceContainer
FdNetDeviceHelper::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>
FdNetDeviceHelper::InstallPriv (Ptr<Node> node) const
{
Ptr<FdNetDevice> device = m_deviceFactory.Create<FdNetDevice> ();
device->SetAddress (Mac48Address::Allocate ());
node->AddDevice (device);
return device;
}
} // namespace ns3

View File

@@ -0,0 +1,134 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2012 INRIA
*
* 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
*
* Author: Alina Quereilhac <alina.quereilhac@inria.fr>
*
*/
#ifndef FD_NET_DEVICE_HELPER_H
#define FD_NET_DEVICE_HELPER_H
#include <string>
#include "ns3/attribute.h"
#include "ns3/fd-net-device.h"
#include "ns3/object-factory.h"
#include "ns3/net-device-container.h"
#include "ns3/node-container.h"
#include "ns3/trace-helper.h"
namespace ns3 {
/**
* \brief build a set of FdNetDevice 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 FdNetDeviceHelper : public PcapHelperForDevice,
public AsciiTraceHelperForDevice
{
public:
/**
* Construct a FdNetDeviceHelper.
*/
FdNetDeviceHelper ();
virtual ~FdNetDeviceHelper ()
{
}
/**
* \param n1 the name of the attribute to set
* \param v1 the value of the attribute to set
*
* Set these attributes on each ns3::FdNetDevice created
* by FdNetDeviceHelper::Install
*/
void SetAttribute (std::string n1, const AttributeValue &v1);
/**
* This method creates a FdNetDevice and associates it to a node
*
* \param node The node to install the device in
* \returns A container holding the added net device.
*/
virtual NetDeviceContainer Install (Ptr<Node> node) const;
/**
* This method creates a FdNetDevice and associates it to a node
*
* \param name The name of the node to install the device in
* \returns A container holding the added net device.
*/
virtual NetDeviceContainer Install (std::string name) const;
/**
* This method creates a FdNetDevice and associates it to a node.
* For each Ptr<node> in the provided container: it creates an ns3::FdNetDevice
* (with the attributes configured by FdNetDeviceHelper::SetDeviceAttribute);
* adds the device to the node; and attaches the channel to the device.
*
* \param c The NodeContainer holding the nodes to be changed.
* \returns A container holding the added net devices.
*/
virtual NetDeviceContainer Install (const NodeContainer &c) const;
protected:
/*
* \internal
*/
virtual Ptr<NetDevice> InstallPriv (Ptr<Node> node) const;
private:
/**
* \brief Enable pcap output on the indicated net device.
* \internal
*
* 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.
*/
virtual void EnableAsciiInternal (Ptr<OutputStreamWrapper> stream,
std::string prefix,
Ptr<NetDevice> nd,
bool explicitFilename);
ObjectFactory m_deviceFactory;
};
} // namespace ns3
#endif /* FD_NET_DEVICE_HELPER_H */

View File

@@ -0,0 +1,343 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2012 INRIA
*
* 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
*
* Author: Alina Quereilhac <alina.quereilhac@inria.fr>
* Claudio Freire <klaussfreire@sourceforge.net>
*
*/
#include "planetlab-fd-net-device-helper.h"
#include "encode-decode.h"
#include "ns3/abort.h"
#include "ns3/config.h"
#include "ns3/fd-net-device.h"
#include "ns3/log.h"
#include "ns3/names.h"
#include "ns3/object-factory.h"
#include "ns3/packet.h"
#include "ns3/simulator.h"
#include "ns3/trace-helper.h"
#include "ns3/internet-module.h"
#include <arpa/inet.h>
#include <errno.h>
#include <iostream>
#include <iomanip>
#include <limits>
#include <linux/if_tun.h>
#include <memory>
#include <net/ethernet.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netpacket/packet.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/ioctl.h>
#include <time.h>
#include <unistd.h>
#include <string>
NS_LOG_COMPONENT_DEFINE ("PlanetLabFdNetDeviceHelper");
namespace ns3 {
#define PLANETLAB_MAGIC 75867
PlanetLabFdNetDeviceHelper::PlanetLabFdNetDeviceHelper ()
{
m_tapIp = Ipv4Address ("255.255.255.255");
m_tapMask = Ipv4Mask ("255.255.255.255");
}
void
PlanetLabFdNetDeviceHelper::SetTapIpAddress (Ipv4Address address)
{
m_tapIp = address;
}
void
PlanetLabFdNetDeviceHelper::SetTapMask (Ipv4Mask mask)
{
m_tapMask = mask;
}
Ptr<NetDevice>
PlanetLabFdNetDeviceHelper::InstallPriv (Ptr<Node> node) const
{
Ptr<NetDevice> d = FdNetDeviceHelper::InstallPriv (node);
Ptr<FdNetDevice> device = d->GetObject<FdNetDevice> ();
//
// The PlanetLab mechanism to create a TAP device doesn't allow
// for the moment to set the IFF_NOPI flag. In consequence, a PI
// header will be present in the traffic.
// We need to explicitly set the encapsulation mode to DIXPI,
// so the FdNetDevice is able to treat correctly the traffic
// traversing TAP device.
//
Ptr<FdNetDevice> fdnd = device->GetObject<FdNetDevice> ();
fdnd->SetEncapsulationMode (FdNetDevice::DIXPI);
SetFileDescriptor (device);
return device;
}
void
PlanetLabFdNetDeviceHelper::SetFileDescriptor (Ptr<FdNetDevice> device) const
{
NS_LOG_LOGIC ("Creating TAP device");
//
// Call out to a separate process running as suid root in order to create a
// TAP device. We do this to avoid having the entire simulation running as root.
//
int fd = CreateFileDescriptor ();
device->SetFileDescriptor (fd);
}
int
PlanetLabFdNetDeviceHelper::CreateFileDescriptor (void) const
{
NS_LOG_FUNCTION (this);
#ifdef HAVE_PLANETLAB_TAP_CREATOR
//
// We're going to fork and exec that program soon, but first we need to have
// a socket to talk to it with. So we create a local interprocess (Unix)
// socket for that purpose.
//
int sock = socket (PF_UNIX, SOCK_DGRAM, 0);
NS_ABORT_MSG_IF (sock == -1, "PlanetLabFdNetDeviceHelper::CreateFileDescriptor(): Unix socket creation error, errno = " << strerror (errno));
//
// Bind to that socket and let the kernel allocate an endpoint
//
struct sockaddr_un un;
memset (&un, 0, sizeof (un));
un.sun_family = AF_UNIX;
int status = bind (sock, (struct sockaddr*)&un, sizeof (sa_family_t));
NS_ABORT_MSG_IF (status == -1, "PlanetLabFdNetDeviceHelper::CreateFileDescriptor(): Could not bind(): errno = " << strerror (errno));
NS_LOG_INFO ("Created Unix socket");
NS_LOG_INFO ("sun_family = " << un.sun_family);
NS_LOG_INFO ("sun_path = " << un.sun_path);
//
// We have a socket here, but we want to get it there -- to the program we're
// going to exec. What we'll do is to do a getsockname and then encode the
// resulting address information as a string, and then send the string to the
// program as an argument. So we need to get the sock name.
//
socklen_t len = sizeof (un);
status = getsockname (sock, (struct sockaddr*)&un, &len);
NS_ABORT_MSG_IF (status == -1, "PlanetLabFdNetDeviceHelper::CreateFileDescriptor(): Could not getsockname(): errno = " << strerror (errno));
//
// Now encode that socket name (family and path) as a string of hex digits
//
std::string path = BufferToString ((uint8_t *)&un, len);
NS_LOG_INFO ("Encoded Unix socket as \"" << path << "\"");
//
// Fork and exec the process to create our socket. If we're us (the parent)
// we wait for the child (the creator) to complete and read the socket it
// created and passed back using the ancillary data mechanism.
//
pid_t pid = ::fork ();
if (pid == 0)
{
NS_LOG_DEBUG ("Child process");
//
// build a command line argument from the encoded endpoint string that
// the socket creation process will use to figure out how to respond to
// the (now) parent process. We're going to have to give this program
// quite a bit of information.
//
// -i<IP-address> The IP address to assign to the new tap device;
// -n<network-prefix> The network prefix to assign to the new tap device;
// -t Set teh IFF_TAP flag
// -p<path> the path to the unix socket described above.
//
// Example tap-creator -i1.2.3.1 -n24 -t -pblah
//
std::ostringstream ossIp;
ossIp << "-i" << m_tapIp;
std::ostringstream ossPrefix;
ossPrefix << "-n" << m_tapMask.GetPrefixLength ();
std::ostringstream ossMode;
ossMode << "-t";
std::ostringstream ossPath;
ossPath << "-p" << path;
//
// Execute the socket creation process image.
//
status = ::execlp (PLANETLAB_TAP_CREATOR,
PLANETLAB_TAP_CREATOR, // argv[0] (filename)
ossIp.str ().c_str (), // argv[1] (-i<IP address>)
ossPrefix.str ().c_str (), // argv[2] (-n<prefix>)
ossMode.str ().c_str (), // argv[3] (-t <tap>)
ossPath.str ().c_str (), // argv[4] (-p<path>)
(char *)NULL);
//
// If the execlp successfully completes, it never returns. If it returns it failed or the OS is
// broken. In either case, we bail.
//
NS_FATAL_ERROR ("PlanetLabFdNetDeviceHelper::CreateFileDescriptor(): Back from execlp(), errno = " << ::strerror (errno));
}
else
{
NS_LOG_DEBUG ("Parent process");
//
// We're the process running the emu net device. We need to wait for the
// socket creator process to finish its job.
//
int st;
pid_t waited = waitpid (pid, &st, 0);
NS_ABORT_MSG_IF (waited == -1, "PlanetLabFdNetDeviceHelper::CreateFileDescriptor(): waitpid() fails, errno = " << strerror (errno));
NS_ASSERT_MSG (pid == waited, "PlanetLabFdNetDeviceHelper::CreateFileDescriptor(): pid mismatch");
//
// Check to see if the socket creator exited normally and then take a
// look at the exit code. If it bailed, so should we. If it didn't
// even exit normally, we bail too.
//
if (WIFEXITED (st))
{
int exitStatus = WEXITSTATUS (st);
NS_ABORT_MSG_IF (exitStatus != 0,
"PlanetLabFdNetDeviceHelper::CreateFileDescriptor(): socket creator exited normally with status " << exitStatus);
}
else
{
NS_FATAL_ERROR ("PlanetLabFdNetDeviceHelper::CreateFileDescriptor(): socket creator exited abnormally");
}
//
// At this point, the socket creator has run successfully and should
// have created our tap device, initialized it with the information we
// passed and sent it back to the socket address we provided. A socket
// (fd) we can use to talk to this tap device should be waiting on the
// Unix socket we set up to receive information back from the creator
// program. We've got to do a bunch of grunt work to get at it, though.
//
// The struct iovec below is part of a scatter-gather list. It describes a
// buffer. In this case, it describes a buffer (an integer) that will
// get the data that comes back from the socket creator process. It will
// be a magic number that we use as a consistency/sanity check.
//
struct iovec iov;
uint32_t 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 receive 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 recvmsg (which we will use to receive 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 the ancillary/control
// data we expect to receive and point it to buffer.
//
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;
//
// Now we can actually receive the interesting bits from the tap
// creator process. Lots of pain to get four bytes.
//
ssize_t bytesRead = recvmsg (sock, &msg, 0);
NS_ABORT_MSG_IF (bytesRead != sizeof(int), "PlanetLabFdNetDeviceHelper::CreateFileDescriptor(): Wrong byte count from socket creator");
//
// There may be a number of message headers/ancillary data arrays coming in.
// Let's look for the one with a type SCM_RIGHTS which indicates it's the
// one we're interested in.
//
struct cmsghdr *cmsg;
for (cmsg = CMSG_FIRSTHDR (&msg); cmsg != NULL; cmsg = CMSG_NXTHDR (&msg, cmsg))
{
if (cmsg->cmsg_level == SOL_SOCKET
&& cmsg->cmsg_type == SCM_RIGHTS)
{
//
// This is the type of message we want. Check to see if the magic
// number is correct and then pull out the socket we care about if
// it matches
//
if (magic == PLANETLAB_MAGIC)
{
NS_LOG_INFO ("Got SCM_RIGHTS with correct magic " << magic);
int *rawSocket = (int*)CMSG_DATA (cmsg);
NS_LOG_INFO ("Got the socket from the socket creator = " << *rawSocket);
return *rawSocket;
}
else
{
NS_LOG_INFO ("Got SCM_RIGHTS, but with bad magic " << magic);
}
}
}
NS_FATAL_ERROR ("Did not get the raw socket from the socket creator");
}
#else
NS_FATAL_ERROR ("PLANETLAB_TAP_CREATOR is not defined in your system.");
#endif /* HAVE_PLANETLAB_CREATOR */
}
} // namespace ns3

View File

@@ -0,0 +1,103 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2012 INRIA
*
* 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
*
* Author: Alina Quereilhac <alina.quereilhac@inria.fr>
* Claudio Freire <klaussfreire@sourceforge.net>
*/
#ifndef PLANETLAB_FD_NET_DEVICE_HELPER_H
#define PLANETLAB_FD_NET_DEVICE_HELPER_H
#include <string>
#include "ns3/attribute.h"
#include "ns3/fd-net-device.h"
#include "ns3/object-factory.h"
#include "ns3/mac48-address.h"
#include "ns3/net-device-container.h"
#include "ns3/node-container.h"
#include "emu-fd-net-device-helper.h"
namespace ns3 {
/**
* \brief build a set of FdNetDevice objects attached to a virtual TAP network
* interface
*
*/
class PlanetLabFdNetDeviceHelper : public EmuFdNetDeviceHelper
{
public:
/**
* Construct a PlanetLabFdNetDeviceHelper.
*/
PlanetLabFdNetDeviceHelper ();
virtual ~PlanetLabFdNetDeviceHelper ()
{
}
/**
* Set the device IPv4 address.
*
* \param address The IPv4 address for the TAP device.
*/
void SetTapIpAddress (Ipv4Address address);
/**
* Set the network mask for the TAP device.
*
* \param mask The network mask for the TAP device.
*/
void SetTapMask (Ipv4Mask mask);
protected:
/*
* \internal
*/
Ptr<NetDevice> InstallPriv (Ptr<Node> node) const;
/**
* Sets a file descriptor on the FileDescriptorNetDevice.
*/
virtual void SetFileDescriptor (Ptr<FdNetDevice> device) const;
/**
* Call out to a separate process running as suid root in order to create a
* TAP device and obtain the file descriptor associated to it.
*/
virtual int CreateFileDescriptor (void) const;
/**
* \internal
*
* The IP address for the TAP device.
*/
Ipv4Address m_tapIp;
/**
* \internal
*
* The network mask for the TAP device.
*/
Ipv4Mask m_tapMask;
};
} // namespace ns3
#endif /* PLANETLAB_FD_NET_DEVICE_HELPER_H */

View File

@@ -0,0 +1,235 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2012 INRIA
*
*
* 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
*
* Author: Alina Quereilhac <alina.quereilhac@inria.fr>
* Claudio Freire <klaussfreire@sourceforge.net>
*
*/
#include <unistd.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <string.h> // for strerror
#include <iostream>
#include <iomanip>
#include <sstream>
#include <errno.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <net/if.h>
#include <linux/if_tun.h>
#include <net/route.h>
#include <netinet/in.h>
#include "creator-utils.h"
#define PLANETLAB_MAGIC 75867
#define VSYS_TUNTAP "/vsys/fd_tuntap.control"
#define VSYS_VIFUP_IN "/vsys/vif_up.in"
#define VSYS_VIFUP_OUT "/vsys/vif_up.out"
using namespace ns3;
/**
*
* Reads vif FD from "fd", writes interface name to vif_name, and returns vif FD.
* vif_name should be IFNAMSIZ chars long.
*
*/
int
ReceiveVifFd (int fd, char *vif_name)
{
struct msghdr msg;
struct iovec iov;
int rv;
size_t ccmsg[CMSG_SPACE (sizeof(int)) / sizeof(size_t)];
struct cmsghdr *cmsg;
/* Use IOV to read interface name */
iov.iov_base = vif_name;
iov.iov_len = IFNAMSIZ;
msg.msg_name = 0;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
/* old BSD implementations should use msg_accrights instead of
* msg_control; the interface is different. */
msg.msg_control = ccmsg;
msg.msg_controllen = sizeof(ccmsg);
while (((rv = recvmsg (fd, &msg, 0)) == -1) && errno == EINTR)
{
}
ABORT_IF (rv == -1, "Could not receive fd from Vsys", 0);
ABORT_IF (!rv, "Could not receive fd from Vsys (EOF)", 0);
cmsg = CMSG_FIRSTHDR (&msg);
ABORT_IF (!cmsg->cmsg_type == SCM_RIGHTS, "got control message of unknown type" << cmsg->cmsg_type, 0);
int* retfd = (int*)CMSG_DATA (cmsg);
return *retfd;
}
/**
*
* Creates a TUN/TAP device on a PlanetLab virtual machine (sliver).
* PlanetLab provides the Vsys API to enable privileged operating system calls
* in an environment with restricted privileges.
* To create a TUN/TAP device the it is necessary to connect to the
* /vsys/fd_tuntap.control socket, and send the device initialization parameters.
*
*/
int
TunAlloc (int iftype, char *if_name)
{
int control_fd;
struct sockaddr_un addr;
int remotefd;
int ret;
control_fd = socket (AF_UNIX, SOCK_STREAM, 0);
ABORT_IF (control_fd == -1, "Could not create UNIX socket", 0);
memset (&addr, 0, sizeof(struct sockaddr_un));
/* Clear structure */
addr.sun_family = AF_UNIX;
strncpy (addr.sun_path, VSYS_TUNTAP, sizeof(addr.sun_path) - 1);
ret = connect (control_fd, (struct sockaddr *) &addr,
sizeof(struct sockaddr_un));
ABORT_IF (ret == -1, "Could not connect to Vsys control socket", 0);
/* passing type param */
ret = send (control_fd, &iftype, sizeof(iftype), 0);
ABORT_IF (ret != sizeof(iftype), "Could not send paramater to Vsys control socket", 0);
return ReceiveVifFd (control_fd, if_name);
}
/**
*
* Sets the TAP/TUN interface up.
* When a TAP/TUN device is created on PlanetLab it must be set up
* writing some configuration information to the vsys fifo at /vsys/vif_up.in
*
*/
void
SetTunUp (const char *ip, const char *prefix, const char *if_name)
{
FILE *in;
FILE *out;
int nbytes;
in = fopen (VSYS_VIFUP_IN, "a");
if (in == NULL)
{
ABORT_IF (in == NULL, "Failed to open " << VSYS_VIFUP_IN, 0);
}
out = fopen (VSYS_VIFUP_DOWN, "r");
if (out == NULL)
{
ABORT_IF (out == NULL, "Failed to open " << VSYS_VIFUP_OUT, 0);
}
// send input to process
fprintf (in, "%s\n%s\n%s\nsnat=1\n", if_name, ip, prefix);
// close pipe to indicate end parameter passing and flush the fifo
fclose (in);
nbytes = fread(if_name, 4096, 1, out);
// the error buffer will not be empty if we read an error
ABORT_IF (strcmp(if_name, "") != 0, if_name, 0);
fclose (out);
return 0;
}
int
main (int argc, char *argv[])
{
int c;
char *ip = NULL;
char *prefix = NULL;
char *path = NULL;
int iftype = IFF_TUN;
char if_name[4096];
memset(if_name, 0, 4096);
opterr = 0;
while ((c = getopt (argc, argv, "vi:n:tp:")) != -1)
{
switch (c)
{
case 'i':
ip = optarg; // ip address of the new device
break;
case 'n':
prefix = optarg; // prefix for the new device
break;
case 't':
iftype = IFF_TAP; // mode for the device (TAP or TUN)
break;
case 'p':
path = optarg; // path back to the tap bridge
break;
case 'v':
gVerbose = true;
break;
}
}
ABORT_IF (ip == NULL, "IP Address is a required argument", 0);
LOG ("Provided IP Address is \"" << ip << "\"");
ABORT_IF (prefix == NULL, "Prefix is a required argument", 0);
LOG ("Provided prefix \"" << prefix << "\"");
ABORT_IF (path == NULL, "path is a required argument", 0);
LOG ("Provided path is \"" << path << "\"");
LOG ("Creating Tap");
// allocate a TAP device in planetLab
int fd = TunAlloc (iftype, if_name);
ABORT_IF (fd == -1, "main(): Unable to create tap device", 1);
// set the TAP interface up
SetTunUp (ip, prefix, (const char*)if_name);
//
// Send the socket back to the tap net device so it can go about its business
//
SendSocket (path, fd, PLANETLAB_MAGIC);
return 0;
}

View File

@@ -0,0 +1,95 @@
/* -*- 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 <stdlib.h>
#include <errno.h>
#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 "creator-utils.h"
#define EMU_MAGIC 65867
using namespace ns3;
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 execute 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, EMU_MAGIC);
return 0;
}

View File

@@ -0,0 +1,426 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2009 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 <arpa/inet.h>
#include <unistd.h>
#include <stdint.h>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <net/if.h>
#include <linux/if_tun.h>
#include <net/route.h>
#include <netinet/in.h>
#include "creator-utils.h"
#define TAP_MAGIC 95549
//
// Lots of the following helper code taken from corresponding functions in src/node.
//
#define ASCII_DOT (0x2e)
#define ASCII_ZERO (0x30)
#define ASCII_a (0x41)
#define ASCII_z (0x5a)
#define ASCII_A (0x61)
#define ASCII_Z (0x7a)
#define ASCII_COLON (0x3a)
#define ASCII_ZERO (0x30)
using namespace ns3;
struct in6_ifreq {
struct in6_addr ifr6_addr;
uint32_t ifr6_prefixlen;
int32_t ifr6_ifindex;
};
char
AsciiToLowCase (char c)
{
if (c >= ASCII_a && c <= ASCII_z)
{
return c;
}
else if (c >= ASCII_A && c <= ASCII_Z)
{
return c + (ASCII_a - ASCII_A);
}
else
{
return c;
}
}
void
AsciiToMac48 (const char *str, uint8_t addr[6])
{
int i = 0;
while (*str != 0 && i < 6)
{
uint8_t byte = 0;
while (*str != ASCII_COLON && *str != 0)
{
byte <<= 4;
char low = AsciiToLowCase (*str);
if (low >= ASCII_a)
{
byte |= low - ASCII_a + 10;
}
else
{
byte |= low - ASCII_ZERO;
}
str++;
}
addr[i] = byte;
i++;
if (*str == 0)
{
break;
}
str++;
}
}
void
SetIpv4 (const char *deviceName, const char *ip, const char *netmask)
{
struct ifreq ifr;
struct sockaddr_in *sin;
int sock = socket(AF_INET, SOCK_DGRAM, 0);
//
// Set the IP address of the new interface/device.
//
memset(&ifr, 0, sizeof(struct ifreq));
strncpy(ifr.ifr_name, deviceName, IFNAMSIZ);
sin = (struct sockaddr_in*) &ifr.ifr_addr;
inet_pton(AF_INET, ip, &sin->sin_addr);
ifr.ifr_addr.sa_family = AF_INET;
ABORT_IF (ioctl (sock, SIOCSIFADDR, &ifr) == -1,
"Could not set IP address", true);
LOG ("Set device IP address to " << ip);
//
// Set the net mask of the new interface/device
//
memset(&ifr, 0, sizeof(struct ifreq));
strncpy(ifr.ifr_name, deviceName, IFNAMSIZ);
sin = (struct sockaddr_in*) &ifr.ifr_netmask;
inet_pton(AF_INET, netmask, &sin->sin_addr);
ifr.ifr_addr.sa_family = AF_INET;
ABORT_IF (ioctl (sock, SIOCSIFNETMASK, &ifr) == -1,
"Could not set net mask", true);
LOG ("Set device Net Mask to " << netmask);
close(sock);
}
void
SetIpv6 (const char* deviceName, const char *ip, int netprefix)
{
struct ifreq ifr;
struct sockaddr_in6 sin;
struct in6_ifreq ifr6;
int sock = socket(AF_INET6, SOCK_DGRAM, 0);
memset(&ifr, 0, sizeof(struct ifreq));
strncpy(ifr.ifr_name, deviceName, IFNAMSIZ);
ABORT_IF (ioctl (sock, SIOGIFINDEX, &ifr) == -1,
"Could not get interface index", true);
LOG ("Set device IP v6 address to " << ip);
memset(&sin, 0, sizeof(struct sockaddr_in6));
sin.sin6_family = AF_INET6;
inet_pton(AF_INET6, ip, (void *) &sin.sin6_addr);
memset(&ifr6, 0, sizeof(in6_ifreq));
memcpy((char *) &ifr6.ifr6_addr, (char *) &sin.sin6_addr, sizeof(struct in6_addr));
ifr6.ifr6_ifindex = ifr.ifr_ifindex;
ifr6.ifr6_prefixlen = netprefix;
//
// Set the IP address of the new interface/device.
//
ABORT_IF (ioctl (sock, SIOCSIFADDR, &ifr6) == -1,
"Could not set IP v6 address", true);
LOG ("Set device IP v6 address to " << ip);
close (sock);
}
void
SetMacAddress (int fd, const char* mac)
{
struct ifreq ifr;
memset(&ifr, 0, sizeof(struct ifreq));
ifr.ifr_hwaddr.sa_family = 1; // this is ARPHRD_ETHER from if_arp.h
AsciiToMac48 (mac, (uint8_t*)ifr.ifr_hwaddr.sa_data);
ABORT_IF (ioctl (fd, SIOCSIFHWADDR, &ifr) == -1, "Could not set MAC address", true);
LOG ("Set device MAC address to " << mac);
}
void
SetUp (char *deviceName)
{
struct ifreq ifr;
int sock = socket(AF_INET, SOCK_DGRAM, 0);
memset(&ifr, 0, sizeof(struct ifreq));
strncpy(ifr.ifr_name, deviceName, IFNAMSIZ);
ABORT_IF (ioctl (sock, SIOCGIFFLAGS, &ifr) == -1,
"Could not get flags for interface", true);
ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
ABORT_IF (ioctl (sock, SIOCSIFFLAGS, &ifr) == -1,
"Could not bring interface up", true);
LOG ("Device is up");
close (sock);
}
int
CreateTap (char *deviceName, const char *mac, const int ifftap, const int iffpi,
const char *ip4, const char *netmask, const char *ip6, const int netprefix)
{
//
// Creation and management of Tap devices is done via the tun device
//
int fd = open ("/dev/net/tun", O_RDWR);
ABORT_IF (fd == -1, "Could not open /dev/net/tun", true);
//
// Set flags for device type and PI header.
//
struct ifreq ifr;
memset(&ifr, 0, sizeof(struct ifreq));
ifr.ifr_flags = (ifftap ? IFF_TAP : IFF_TUN);
if (!iffpi)
{
ifr.ifr_flags |= IFF_NO_PI;
}
//
// If device name is not specified, the kernel chooses one.
//
if (*deviceName)
{
strncpy(ifr.ifr_name, deviceName, IFNAMSIZ);
}
ABORT_IF (ioctl (fd, TUNSETIFF, (void *) &ifr) == -1,
"Could not allocate tap device", true);
LOG ("Allocated TAP device " << deviceName);
//
// Set the hardware (MAC) address of the new device
//
if (ifftap)
{
SetMacAddress(fd, mac);
}
//
// Set the IP address and netmask of the new interface/device.
//
if (ip4)
{
SetIpv4(deviceName, ip4, netmask);
}
if (ip6)
{
SetIpv6(deviceName, ip6, netprefix);
}
//
// Bring the interface up.
//
SetUp(deviceName);
return fd;
}
int
main (int argc, char *argv[])
{
int c;
char *dev = NULL;
char *ip4 = NULL;
char *ip6 = NULL;
char *mac = NULL;
char *netmask = NULL;
char *path = NULL;
int tap = false;
int pi = false;
int prefix = NULL;
while ((c = getopt (argc, argv, "vd:i:m:n:I:P:thp:")) != -1)
{
switch (c)
{
case 'd':
dev = optarg; // name of the new tap device
break;
case 'i':
ip4 = optarg; // ip v4 address of the new device
break;
case 'I':
ip6 = optarg; // ip v6 address of the new device
break;
case 'm':
mac = optarg; // mac address of the new device
break;
case 'n':
netmask = optarg; // ip v4 net mask for the new device
break;
case 'P':
prefix = atoi(optarg); // ip v6 prefix for the new device
break;
case 't':
tap = true; // mode for the device (TAP or TUN)
break;
case 'h':
pi = true; // set the IFF_NO_PI flag
break;
case 'p':
path = optarg; // path back to the tap bridge
break;
case 'v':
gVerbose = true;
break;
}
}
//
// We have got to be able to coordinate the name of the tap device we are
// going to create and or open with the device that an external Linux host
// will use. If this name is provided we use it. If not we let the system
// create the device for us. This name is given in dev
//
LOG ("Provided Device Name is \"" << dev << "\"");
//
// We have got to be able to assign an IP address to the tap device we are
// allocating. This address is allocated in the simulation and assigned to
// the tap bridge. This address is given in ip.
//
ABORT_IF (ip4 == NULL && ip6 == NULL, "IP Address is a required argument", 0);
if (ip4)
{
ABORT_IF (netmask == NULL, "Net mask is a required argument", 0);
LOG ("Provided IP v4 Address is \"" << ip4 << "\"");
LOG ("Provided IP v4 Net Mask is \"" << netmask << "\"");
}
if (ip6)
{
ABORT_IF (prefix == NULL, "Prefix is a required argument", 0);
LOG ("Provided IP v6 Address is \"" << ip6 << "\"");
LOG ("Provided IP v6 Prefix is \"" << prefix << "\"");
}
//
// We have got to be able to assign a Mac address to the tap device we are
// allocating. This address is allocated in the simulation and assigned to
// the bridged device. This allows packets addressed to the bridged device
// to appear in the Linux host as if they were received there.
//
ABORT_IF (mac == NULL, "MAC Address is a required argument", 0);
LOG ("Provided MAC Address is \"" << mac << "\"");
//
// We have got to know whether or not to create the TAP.
//
if (tap)
{
LOG ("Provided device Mode is TAP");
}
else
{
LOG ("Provided device Mode is TUN");
}
//
// IFF_NO_PI flag.
//
if (pi)
{
LOG ("IFF_NO_PI flag set. Packet Information will be present in the traffic");
}
//
// This program is spawned by a tap bridge running in a simulation. It
// wants to create a socket as described below. We are going to do the
// work here since we're running suid root. Once we create the socket,
// we have to send it back to the tap bridge. We do that over a Unix
// (local interprocess) socket. The tap bridge 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 futz with the
// Tap device underlying all of this. So all of these hoops are to allow
// us to execute the following code:
//
LOG ("Creating Tap");
int sock = CreateTap (dev, mac, tap, pi, ip4, netmask, ip6, prefix);
ABORT_IF (sock == -1, "main(): Unable to create tap socket", 1);
//
// Send the socket back to the tap net device so it can go about its business
//
SendSocket (path, sock, TAP_MAGIC);
return 0;
}

View File

@@ -0,0 +1,414 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2012 INRIA, 2012 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 "tap-fd-net-device-helper.h"
#include "encode-decode.h"
#include "ns3/abort.h"
#include "ns3/config.h"
#include "ns3/fd-net-device.h"
#include "ns3/log.h"
#include "ns3/names.h"
#include "ns3/object-factory.h"
#include "ns3/packet.h"
#include "ns3/simulator.h"
#include "ns3/trace-helper.h"
#include "ns3/internet-module.h"
#include <arpa/inet.h>
#include <errno.h>
#include <iostream>
#include <iomanip>
#include <limits>
#include <linux/if_tun.h>
#include <memory>
#include <net/ethernet.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netpacket/packet.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/ioctl.h>
#include <time.h>
#include <unistd.h>
#include <string>
NS_LOG_COMPONENT_DEFINE ("TapFdNetDeviceHelper");
namespace ns3 {
#define TAP_MAGIC 95549
TapFdNetDeviceHelper::TapFdNetDeviceHelper ()
{
m_deviceName = "";
m_modePi = false;
m_tapIp4 = "";
m_tapMask4 = "";
m_tapIp6 = "";
m_tapPrefix6 = 64;
m_tapMac = Mac48Address::Allocate ();
}
void
TapFdNetDeviceHelper::SetModePi (bool modePi)
{
m_modePi = modePi;
}
void
TapFdNetDeviceHelper::SetTapIpv4Address (Ipv4Address address)
{
m_tapIp4 = address;
}
void
TapFdNetDeviceHelper::SetTapIpv4Mask (Ipv4Mask mask)
{
m_tapMask4 = mask;
}
void
TapFdNetDeviceHelper::SetTapIpv6Address (Ipv6Address address)
{
m_tapIp6 = address;
}
void
TapFdNetDeviceHelper::SetTapIpv6Prefix (int prefix)
{
m_tapPrefix6 = prefix;
}
void
TapFdNetDeviceHelper::SetTapMacAddress (Mac48Address mac)
{
m_tapMac = mac;
}
Ptr<NetDevice>
TapFdNetDeviceHelper::InstallPriv (Ptr<Node> node) const
{
Ptr<NetDevice> d = FdNetDeviceHelper::InstallPriv (node);
Ptr<FdNetDevice> device = d->GetObject<FdNetDevice> ();
Ptr<FdNetDevice> fdnd = device->GetObject<FdNetDevice> ();
//
// We need to explicitly set the encapsulation mode for the traffic
// traversing the TAP device, so the FdNetDevice is able to know
// how to treat the traffic in a way that in compatible with the
// TAP device.
//
if (m_modePi)
{
fdnd->SetEncapsulationMode (FdNetDevice::DIXPI);
}
SetFileDescriptor (device);
return device;
}
void
TapFdNetDeviceHelper::SetFileDescriptor (Ptr<FdNetDevice> device) const
{
NS_LOG_LOGIC ("Creating TAP device");
//
// Call out to a separate process running as suid root in order to create a
// TAP device. We do this to avoid having the entire simulation running as root.
//
int fd = CreateFileDescriptor ();
device->SetFileDescriptor (fd);
}
int
TapFdNetDeviceHelper::CreateFileDescriptor (void) const
{
NS_LOG_FUNCTION (this);
#ifdef HAVE_TAP_CREATOR
//
// We're going to fork and exec that program soon, but first we need to have
// a socket to talk to it with. So we create a local interprocess (Unix)
// socket for that purpose.
//
int sock = socket (PF_UNIX, SOCK_DGRAM, 0);
NS_ABORT_MSG_IF (sock == -1, "TapFdNetDeviceHelper::CreateFileDescriptor(): Unix socket creation error, errno = " << strerror (errno));
//
// Bind to that socket and let the kernel allocate an endpoint
//
struct sockaddr_un un;
memset (&un, 0, sizeof (un));
un.sun_family = AF_UNIX;
int status = bind (sock, (struct sockaddr*)&un, sizeof (sa_family_t));
NS_ABORT_MSG_IF (status == -1, "TapFdNetDeviceHelper::CreateFileDescriptor(): Could not bind(): errno = " << strerror (errno));
NS_LOG_INFO ("Created Unix socket");
NS_LOG_INFO ("sun_family = " << un.sun_family);
NS_LOG_INFO ("sun_path = " << un.sun_path);
//
// We have a socket here, but we want to get it there -- to the program we're
// going to exec. What we'll do is to do a getsockname and then encode the
// resulting address information as a string, and then send the string to the
// program as an argument. So we need to get the sock name.
//
socklen_t len = sizeof (un);
status = getsockname (sock, (struct sockaddr*)&un, &len);
NS_ABORT_MSG_IF (status == -1, "TapFdNetDeviceHelper::CreateFileDescriptor(): Could not getsockname(): errno = " << strerror (errno));
//
// Now encode that socket name (family and path) as a string of hex digits
//
std::string path = BufferToString ((uint8_t *)&un, len);
NS_LOG_INFO ("Encoded Unix socket as \"" << path << "\"");
//
// Fork and exec the process to create our socket. If we're us (the parent)
// we wait for the child (the creator) to complete and read the socket it
// created and passed back using the ancillary data mechanism.
//
pid_t pid = ::fork ();
if (pid == 0)
{
NS_LOG_DEBUG ("Child process");
//
// build a command line argument from the encoded endpoint string that
// the socket creation process will use to figure out how to respond to
// the (now) parent process. We're going to have to give this program
// quite a bit of information.
//
// -d<device-name> The name of the tap device we want to create;
// -m<MAC-address> The MAC-48 address to assign to the new tap device;
// -i<IPv4-address> The IP v4 address to assign to the new tap device;
// -I<IPv6-address> The IP v6 address to assign to the new tap device;
// -n<network-IPv4-mask> The network IPv4 mask to assign to the new tap device;
// -N<network-IPv6-mask> The network IPv6 mask to assign to the new tap device;
// -t Set teh IFF_TAP flag
// -h Set the IFF_NO_PI flag
// -p<path> the path to the unix socket described above.
//
// Example tap-creator -dnewdev -i1.2.3.1 -m08:00:2e:00:01:23 -n255.255.255.0 -t -h -pblah
//
//
// The device-name is something we may want the system to make up in
// every case. We also rely on it being configured via an Attribute
// through the helper. By default, it is set to the empty string
// which tells the system to make up a device name such as "tap123".
//
std::ostringstream ossDeviceName;
if (m_deviceName != "")
{
ossDeviceName << "-d" << m_deviceName;
}
std::ostringstream ossMac;
ossMac << "-m" << m_tapMac;
std::ostringstream ossIp4;
if (m_tapIp4 != "")
{
ossIp4 << "-i" << m_tapIp4;
}
std::ostringstream ossIp6;
if (m_tapIp6 != "")
{
ossIp6 << "-I" << m_tapIp6;
}
std::ostringstream ossNetmask4;
if (m_tapMask4 != "" )
{
ossNetmask4 << "-n" << m_tapMask4;
}
std::ostringstream ossPrefix6;
ossPrefix6 << "-P" << m_tapPrefix6;
std::ostringstream ossMode;
ossMode << "-t";
std::ostringstream ossPI;
if (m_modePi)
{
ossPI << "-h";
}
std::ostringstream ossPath;
ossPath << "-p" << path;
//
// Execute the socket creation process image.
//
status = ::execlp (TAP_CREATOR,
TAP_CREATOR, // argv[0] (filename)
ossDeviceName.str ().c_str (), // argv[1] (-d<device name>)
ossMac.str ().c_str (), // argv[2] (-m<MAC address>
ossIp4.str ().c_str (), // argv[3] (-i<IP v4 address>)
ossIp6.str ().c_str (), // argv[4] (-I<IP v6 address>)
ossNetmask4.str ().c_str (), // argv[5] (-n<IP v4 net mask>)
ossPrefix6.str ().c_str (), // argv[6] (-P<IP v6 prefix>)
ossMode.str ().c_str (), // argv[7] (-t <tap>)
ossPI.str ().c_str (), // argv[8] (-h <pi>)
ossPath.str ().c_str (), // argv[9] (-p<path>)
(char *)NULL);
//
// If the execlp successfully completes, it never returns. If it returns it failed or the OS is
// broken. In either case, we bail.
//
NS_FATAL_ERROR ("TapFdNetDeviceHelper::CreateFileDescriptor(): Back from execlp(), errno = " << ::strerror (errno));
}
else
{
NS_LOG_DEBUG ("Parent process");
//
// We're the process running the emu net device. We need to wait for the
// socket creator process to finish its job.
//
int st;
pid_t waited = waitpid (pid, &st, 0);
NS_ABORT_MSG_IF (waited == -1, "TapFdNetDeviceHelper::CreateFileDescriptor(): waitpid() fails, errno = " << strerror (errno));
NS_ASSERT_MSG (pid == waited, "TapFdNetDeviceHelper::CreateFileDescriptor(): pid mismatch");
//
// Check to see if the socket creator exited normally and then take a
// look at the exit code. If it bailed, so should we. If it didn't
// even exit normally, we bail too.
//
if (WIFEXITED (st))
{
int exitStatus = WEXITSTATUS (st);
NS_ABORT_MSG_IF (exitStatus != 0,
"TapFdNetDeviceHelper::CreateFileDescriptor(): socket creator exited normally with status " << exitStatus);
}
else
{
NS_FATAL_ERROR ("TapFdNetDeviceHelper::CreateFileDescriptor(): socket creator exited abnormally");
}
//
// At this point, the socket creator has run successfully and should
// have created our tap device, initialized it with the information we
// passed and sent it back to the socket address we provided. A socket
// (fd) we can use to talk to this tap device should be waiting on the
// Unix socket we set up to receive information back from the creator
// program. We've got to do a bunch of grunt work to get at it, though.
//
// The struct iovec below is part of a scatter-gather list. It describes a
// buffer. In this case, it describes a buffer (an integer) that will
// get the data that comes back from the socket creator process. It will
// be a magic number that we use as a consistency/sanity check.
//
struct iovec iov;
uint32_t 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 receive 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 recvmsg (which we will use to receive 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 the ancillary/control
// data we expect to receive and point it to buffer.
//
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;
//
// Now we can actually receive the interesting bits from the tap
// creator process. Lots of pain to get four bytes.
//
ssize_t bytesRead = recvmsg (sock, &msg, 0);
NS_ABORT_MSG_IF (bytesRead != sizeof(int), "TapFdNetDeviceHelper::CreateFileDescriptor(): Wrong byte count from socket creator");
//
// There may be a number of message headers/ancillary data arrays coming in.
// Let's look for the one with a type SCM_RIGHTS which indicates it's the
// one we're interested in.
//
struct cmsghdr *cmsg;
for (cmsg = CMSG_FIRSTHDR (&msg); cmsg != NULL; cmsg = CMSG_NXTHDR (&msg, cmsg))
{
if (cmsg->cmsg_level == SOL_SOCKET
&& cmsg->cmsg_type == SCM_RIGHTS)
{
//
// This is the type of message we want. Check to see if the magic
// number is correct and then pull out the socket we care about if
// it matches
//
if (magic == TAP_MAGIC)
{
NS_LOG_INFO ("Got SCM_RIGHTS with correct magic " << magic);
int *rawSocket = (int*)CMSG_DATA (cmsg);
NS_LOG_INFO ("Got the socket from the socket creator = " << *rawSocket);
return *rawSocket;
}
else
{
NS_LOG_INFO ("Got SCM_RIGHTS, but with bad magic " << magic);
}
}
}
NS_FATAL_ERROR ("Did not get the raw socket from the socket creator");
}
#else
NS_FATAL_ERROR ("TAP_CREATOR is not defined in your system.");
#endif /* HAVE_TAP_CREATOR */
}
} // namespace ns3

View File

@@ -0,0 +1,159 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2012 INRIA, 2012 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 TAP_FD_NET_DEVICE_HELPER_H
#define TAP_FD_NET_DEVICE_HELPER_H
#include <string>
#include "ns3/attribute.h"
#include "ns3/fd-net-device.h"
#include "ns3/object-factory.h"
#include "ns3/mac48-address.h"
#include "ns3/net-device-container.h"
#include "ns3/node-container.h"
#include "emu-fd-net-device-helper.h"
namespace ns3 {
/**
* \brief build a set of FdNetDevice objects attached to a virtua TAP network
* interface
*
*/
class TapFdNetDeviceHelper : public EmuFdNetDeviceHelper
{
public:
/**
* Construct a TapFdNetDeviceHelper.
*/
TapFdNetDeviceHelper ();
virtual ~TapFdNetDeviceHelper ()
{
}
/**
* Set flag IFF_NO_PI on the device.
*
* \param pi Set the IFF_NO_PI flag if pi is false.
*/
void SetModePi (bool pi);
/**
* Set the device IPv4 address.
*
* \param address The IPv4 address for the TAP device.
*/
void SetTapIpv4Address (Ipv4Address address);
/**
* Set the IPv4 network mask for the TAP device.
*
* \param mask The IPv4 network mask for the TAP device.
*/
void SetTapIpv4Mask (Ipv4Mask mask);
/**
* Set the device IPv6 address.
*
* \param address The IPv6 address for the TAP device.
*/
void SetTapIpv6Address (Ipv6Address address);
/**
* Set the IPv6 network mask for the TAP device.
*
* \param prefix The IPv6 network prefix for the TAP device.
*/
void SetTapIpv6Prefix (int prefix);
/**
* Set the MAC address for the TAP device.
*
* \param mac The MAC address the TAP device.
*/
void SetTapMacAddress (Mac48Address mac);
protected:
/*
* \internal
*/
Ptr<NetDevice> InstallPriv (Ptr<Node> node) const;
/**
* Sets a file descriptor on the FileDescriptorNetDevice.
*/
virtual void SetFileDescriptor (Ptr<FdNetDevice> device) const;
/**
* Call out to a separate process running as suid root in order to create a
* TAP device and obtain the file descriptor associated to it.
*/
virtual int CreateFileDescriptor (void) const;
/**
* \internal
*
* The TAP device flag IFF_NO_PI.
*/
bool m_modePi;
/**
* \internal
*
* The IPv4 address for the TAP device.
*/
Ipv4Address m_tapIp4;
/**
* \internal
*
* The IPv6 address for the TAP device.
*/
Ipv6Address m_tapIp6;
/**
* \internal
*
* The network mask IPv4 for the TAP device.
*/
Ipv4Mask m_tapMask4;
/**
* \internal
*
* The network prefix IPv6 for the TAP device.
*/
int m_tapPrefix6;
/**
* \internal
*
* The TAP device MAC address.
*/
Mac48Address m_tapMac;
};
} // namespace ns3
#endif /* TAP_FD_NET_DEVICE_HELPER_H */

View File

@@ -0,0 +1,718 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2012 INRIA, 2012 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
*
* Author: Alina Quereilhac <alina.quereilhac@inria.fr>
* Claudio Freire <klaussfreire@sourceforge.net>
*/
#include "fd-net-device.h"
#include "ns3/abort.h"
#include "ns3/boolean.h"
#include "ns3/channel.h"
#include "ns3/enum.h"
#include "ns3/ethernet-header.h"
#include "ns3/ethernet-trailer.h"
#include "ns3/log.h"
#include "ns3/llc-snap-header.h"
#include "ns3/mac48-address.h"
#include "ns3/pointer.h"
#include "ns3/simulator.h"
#include "ns3/string.h"
#include "ns3/trace-source-accessor.h"
#include "ns3/uinteger.h"
#include <unistd.h>
#include <arpa/inet.h>
#include <net/ethernet.h>
NS_LOG_COMPONENT_DEFINE ("FdNetDevice");
namespace ns3 {
FdNetDeviceFdReader::FdNetDeviceFdReader ()
: m_bufferSize (65536) // Defaults to maximum TCP window size
{
}
void
FdNetDeviceFdReader::SetBufferSize (uint32_t bufferSize)
{
m_bufferSize = bufferSize;
}
FdReader::Data FdNetDeviceFdReader::DoRead (void)
{
NS_LOG_FUNCTION (this);
uint8_t *buf = (uint8_t *)malloc (m_bufferSize);
NS_ABORT_MSG_IF (buf == 0, "malloc() failed");
NS_LOG_LOGIC ("Calling read on fd " << m_fd);
ssize_t len = read (m_fd, buf, m_bufferSize);
if (len <= 0)
{
free (buf);
buf = 0;
len = 0;
}
return FdReader::Data (buf, len);
}
NS_OBJECT_ENSURE_REGISTERED (FdNetDevice);
TypeId
FdNetDevice::GetTypeId (void)
{
static TypeId tid = TypeId ("ns3::FdNetDevice")
.SetParent<NetDevice> ()
.AddConstructor<FdNetDevice> ()
.AddAttribute ("Address",
"The MAC address of this device.",
Mac48AddressValue (Mac48Address ("ff:ff:ff:ff:ff:ff")),
MakeMac48AddressAccessor (&FdNetDevice::m_address),
MakeMac48AddressChecker ())
.AddAttribute ("Start",
"The simulation time at which to spin up the device thread.",
TimeValue (Seconds (0.)),
MakeTimeAccessor (&FdNetDevice::m_tStart),
MakeTimeChecker ())
.AddAttribute ("Stop",
"The simulation time at which to tear down the device thread.",
TimeValue (Seconds (0.)),
MakeTimeAccessor (&FdNetDevice::m_tStop),
MakeTimeChecker ())
.AddAttribute ("EncapsulationMode",
"The link-layer encapsulation type to use.",
EnumValue (DIX),
MakeEnumAccessor (&FdNetDevice::m_encapMode),
MakeEnumChecker (DIX, "Dix",
LLC, "Llc",
DIXPI, "DixPi"))
.AddAttribute ("RxQueueSize", "Maximum size of the read queue. "
"This value limits number of packets that have been read "
"from the network into a memory buffer but have not yet "
"been processed by the simulator.",
UintegerValue (1000),
MakeUintegerAccessor (&FdNetDevice::m_maxPendingReads),
MakeUintegerChecker<uint32_t> ())
//
// Trace sources at the "top" of the net device, where packets transition
// to/from higher layers. These points do not really correspond to the
// MAC layer of the underlying operating system, but exist to provide
// a consitent tracing environment. These trace hooks should really be
// interpreted as the points at which a packet leaves the ns-3 environment
// destined for the underlying operating system or vice-versa.
//
.AddTraceSource ("MacTx",
"Trace source indicating a packet has arrived for transmission by this device",
MakeTraceSourceAccessor (&FdNetDevice::m_macTxTrace))
.AddTraceSource ("MacTxDrop",
"Trace source indicating a packet has been dropped by the device before transmission",
MakeTraceSourceAccessor (&FdNetDevice::m_macTxDropTrace))
.AddTraceSource ("MacPromiscRx",
"A packet has been received by this device, has been passed up from the physical layer "
"and is being forwarded up the local protocol stack. This is a promiscuous trace,",
MakeTraceSourceAccessor (&FdNetDevice::m_macPromiscRxTrace))
.AddTraceSource ("MacRx",
"A packet has been received by this device, has been passed up from the physical layer "
"and is being forwarded up the local protocol stack. This is a non-promiscuous trace,",
MakeTraceSourceAccessor (&FdNetDevice::m_macRxTrace))
//
// Trace sources designed to simulate a packet sniffer facility (tcpdump).
//
.AddTraceSource ("Sniffer",
"Trace source simulating a non-promiscuous packet sniffer attached to the device",
MakeTraceSourceAccessor (&FdNetDevice::m_snifferTrace))
.AddTraceSource ("PromiscSniffer",
"Trace source simulating a promiscuous packet sniffer attached to the device",
MakeTraceSourceAccessor (&FdNetDevice::m_promiscSnifferTrace))
;
return tid;
}
FdNetDevice::FdNetDevice ()
: m_node (0),
m_ifIndex (0),
m_mtu (1500), // Defaults to Ethernet v2 MTU
m_fd (-1),
m_fdReader (0),
m_isBroadcast (true),
m_isMulticast (false),
m_pendingReadCount (0),
m_startEvent (),
m_stopEvent ()
{
NS_LOG_FUNCTION (this);
Start (m_tStart);
}
FdNetDevice::FdNetDevice (FdNetDevice const &)
{
}
FdNetDevice::~FdNetDevice ()
{
NS_LOG_FUNCTION (this);
}
void
FdNetDevice::DoDispose (void)
{
NS_LOG_FUNCTION (this);
StopDevice ();
NetDevice::DoDispose ();
}
void
FdNetDevice::SetEncapsulationMode (enum EncapsulationMode mode)
{
NS_LOG_FUNCTION (mode);
m_encapMode = mode;
NS_LOG_LOGIC ("m_encapMode = " << m_encapMode);
}
FdNetDevice::EncapsulationMode
FdNetDevice::GetEncapsulationMode (void) const
{
NS_LOG_FUNCTION (this);
return m_encapMode;
}
void
FdNetDevice::Start (Time tStart)
{
NS_LOG_FUNCTION (tStart);
Simulator::Cancel (m_startEvent);
m_startEvent = Simulator::Schedule (tStart, &FdNetDevice::StartDevice, this);
}
void
FdNetDevice::Stop (Time tStop)
{
NS_LOG_FUNCTION (tStop);
Simulator::Cancel (m_stopEvent);
m_startEvent = Simulator::Schedule (tStop, &FdNetDevice::StopDevice, this);
}
void
FdNetDevice::StartDevice (void)
{
NS_LOG_FUNCTION (this);
if (m_fd == -1)
{
NS_LOG_DEBUG ("FdNetDevice::Start(): Failure, invalid file descriptor.");
return;
}
//
// A similar story exists for the node ID. We can't just naively do a
// GetNode ()->GetId () since GetNode is going to give us a Ptr<Node> which
// is reference counted. We need to stash away the node ID for use in the
// read thread.
//
m_nodeId = GetNode ()->GetId ();
m_fdReader = Create<FdNetDeviceFdReader> ();
m_fdReader->SetBufferSize(m_mtu);
m_fdReader->Start (m_fd, MakeCallback (&FdNetDevice::ReceiveCallback, this));
NotifyLinkUp ();
}
void
FdNetDevice::StopDevice (void)
{
NS_LOG_FUNCTION (this);
if (m_fdReader != 0)
{
m_fdReader->Stop ();
m_fdReader = 0;
}
if (m_fd != -1)
{
close (m_fd);
m_fd = -1;
}
}
void
FdNetDevice::ReceiveCallback (uint8_t *buf, ssize_t len)
{
NS_LOG_FUNCTION (this << buf << len);
bool skip = false;
{
CriticalSection cs (m_pendingReadMutex);
if (m_pendingReadCount >= m_maxPendingReads)
{
//XXX: Packet dropped!
skip = true;
}
else
{
++m_pendingReadCount;
}
}
if (skip)
{
struct timespec time = { 0, 100000000L }; // 100 ms
nanosleep (&time, NULL);
}
else
{
Simulator::ScheduleWithContext (m_nodeId, Time (0), MakeEvent (&FdNetDevice::ForwardUp, this, buf, len));
}
}
// XXX: Consider having a instance member m_packetBuffer and using memmove
// instead of memcpy to add the PI header.
// It might be faster in this case to use memmove and avoid the extra mallocs.
static void
AddPIHeader (uint8_t *&buf, ssize_t &len)
{
// Synthesize PI header for our friend the kernel
uint8_t *buf2 = (uint8_t*)malloc (len + 4);
memcpy (buf2 + 4, buf, len);
len += 4;
// PI = 16 bits flags (0) + 16 bits proto
// NOTE: be careful to interpret buffer data explicitly as
// little-endian to be insensible to native byte ordering.
uint16_t flags = 0;
uint16_t proto = 0x0008; // default to IPv4
if (len > 14)
{
if (buf[12] == 0x81 && buf[13] == 0x00 && len > 18)
{
// tagged ethernet packet
proto = buf[16] | (buf[17] << 8);
}
else
{
// untagged ethernet packet
proto = buf[12] | (buf[13] << 8);
}
}
buf2[0] = (uint8_t)flags;
buf2[1] = (uint8_t)(flags >> 8);
buf2[2] = (uint8_t)proto;
buf2[3] = (uint8_t)(proto >> 8);
// swap buffer
free (buf);
buf = buf2;
}
static void
RemovePIHeader (uint8_t *&buf, ssize_t &len)
{
// strip PI header if present, shrink buffer
if (len >= 4)
{
len -= 4;
memmove (buf, buf + 4, len);
buf = (uint8_t*)realloc (buf, len);
}
}
void
FdNetDevice::ForwardUp (uint8_t *buf, ssize_t len)
{
NS_LOG_FUNCTION (this << buf << len);
if (m_pendingReadCount > 0)
{
{
CriticalSection cs (m_pendingReadMutex);
--m_pendingReadCount;
}
}
// We need to remove the PI header and ignore it
if (m_encapMode == DIXPI)
{
RemovePIHeader (buf, len);
}
//
// Create a packet out of the buffer we received and free that buffer.
//
Ptr<Packet> packet = Create<Packet> (reinterpret_cast<const uint8_t *> (buf), len);
free (buf);
buf = 0;
//
// Trace sinks will expect complete packets, not packets without some of the
// headers
//
Ptr<Packet> originalPacket = packet->Copy ();
Mac48Address destination;
Mac48Address source;
uint16_t protocol;
bool isBroadcast = false;
bool isMulticast = false;
EthernetHeader header (false);
//
// This device could be running in an environment where completely unexpected
// kinds of packets are flying around, so we need to harden things a bit and
// filter out packets we think are completely bogus, so we always check to see
// that the packet is long enough to contain the header we want to remove.
//
if (packet->GetSize () < header.GetSerializedSize ())
{
m_phyRxDropTrace (originalPacket);
return;
}
packet->RemoveHeader (header);
destination = header.GetDestination ();
source = header.GetSource ();
isBroadcast = header.GetDestination ().IsBroadcast ();
isMulticast = header.GetDestination ().IsGroup ();
protocol = header.GetLengthType ();
//
// If the length/type is less than 1500, it corresponds to a length
// interpretation packet. In this case, it is an 802.3 packet and
// will also have an 802.2 LLC header. If greater than 1500, we
// find the protocol number (Ethernet type) directly.
//
if (m_encapMode == LLC and header.GetLengthType () <= 1500)
{
LlcSnapHeader llc;
//
// Check to see that the packet is long enough to possibly contain the
// header we want to remove before just naively calling.
//
if (packet->GetSize () < llc.GetSerializedSize ())
{
m_phyRxDropTrace (originalPacket);
return;
}
packet->RemoveHeader (llc);
protocol = llc.GetType ();
}
NS_LOG_LOGIC ("Pkt source is " << source);
NS_LOG_LOGIC ("Pkt destination is " << destination);
PacketType packetType;
if (isBroadcast)
{
packetType = NS3_PACKET_BROADCAST;
}
else if (isMulticast)
{
packetType = NS3_PACKET_MULTICAST;
}
else if (destination == m_address)
{
packetType = NS3_PACKET_HOST;
}
else
{
packetType = NS3_PACKET_OTHERHOST;
}
//
// For all kinds of packetType we receive, we hit the promiscuous sniffer
// hook and pass a copy up to the promiscuous callback. Pass a copy to
// make sure that nobody messes with our packet.
//
m_promiscSnifferTrace (originalPacket);
if (!m_promiscRxCallback.IsNull ())
{
m_macPromiscRxTrace (originalPacket);
m_promiscRxCallback (this, packet, protocol, source, destination,
packetType);
}
//
// If this packet is not destined for some other host, it must be for us
// as either a broadcast, multicast or unicast. We need to hit the mac
// packet received trace hook and forward the packet up the stack.
//
if (packetType != NS3_PACKET_OTHERHOST)
{
m_snifferTrace (originalPacket);
m_macRxTrace (originalPacket);
m_rxCallback (this, packet, protocol, source);
}
}
bool
FdNetDevice::Send (Ptr<Packet> packet, const Address& destination, uint16_t protocolNumber)
{
NS_LOG_FUNCTION (this << packet << destination << protocolNumber);
return SendFrom (packet, m_address, destination, protocolNumber);
}
bool
FdNetDevice::SendFrom (Ptr<Packet> packet, const Address& src, const Address& dest, uint16_t protocolNumber)
{
NS_LOG_FUNCTION (this << packet << src << dest << protocolNumber);
NS_LOG_LOGIC ("packet " << packet);
NS_LOG_LOGIC ("UID is " << packet->GetUid ());
if (IsLinkUp () == false)
{
m_macTxDropTrace (packet);
return false;
}
Mac48Address destination = Mac48Address::ConvertFrom (dest);
Mac48Address source = Mac48Address::ConvertFrom (src);
NS_LOG_LOGIC ("Transmit packet with UID " << packet->GetUid ());
NS_LOG_LOGIC ("Transmit packet from " << source);
NS_LOG_LOGIC ("Transmit packet to " << destination);
EthernetHeader header (false);
header.SetSource (source);
header.SetDestination (destination);
if (m_encapMode == LLC)
{
LlcSnapHeader llc;
llc.SetType (protocolNumber);
packet->AddHeader (llc);
header.SetLengthType (packet->GetSize ());
}
else
{
header.SetLengthType (protocolNumber);
}
packet->AddHeader (header);
//
// there's not much meaning associated with the different layers in this
// device, so don't be surprised when they're all stacked together in
// essentially one place. We do this for trace consistency across devices.
//
m_macTxTrace (packet);
m_promiscSnifferTrace (packet);
m_snifferTrace (packet);
NS_LOG_LOGIC ("calling write");
NS_ASSERT_MSG (packet->GetSize () <= m_mtu, "FdNetDevice::SendFrom(): Packet too big " << packet->GetSize ());
ssize_t len = (ssize_t) packet->GetSize ();
uint8_t *buffer = (uint8_t*)malloc (len);
packet->CopyData (buffer, len);
// We need to add the PI header
if (m_encapMode == DIXPI)
{
AddPIHeader (buffer, len);
}
ssize_t written = write (m_fd, buffer, len);
free (buffer);
if (written == -1 || written != len)
{
m_macTxDropTrace (packet);
return false;
}
return true;
}
void
FdNetDevice::SetFileDescriptor (int fd)
{
if (m_fd == -1 and fd > 0)
{
m_fd = fd;
}
}
void
FdNetDevice::SetAddress (Address address)
{
m_address = Mac48Address::ConvertFrom (address);
}
Address
FdNetDevice::GetAddress (void) const
{
return m_address;
}
void
FdNetDevice::NotifyLinkUp (void)
{
m_linkUp = true;
m_linkChangeCallbacks ();
}
void
FdNetDevice::SetIfIndex (const uint32_t index)
{
m_ifIndex = index;
}
uint32_t
FdNetDevice::GetIfIndex (void) const
{
return m_ifIndex;
}
Ptr<Channel>
FdNetDevice::GetChannel (void) const
{
return NULL;
}
bool
FdNetDevice::SetMtu (const uint16_t mtu)
{
// The MTU depends on the technology associated to
// the file descriptor. The user is responsible of
// setting the correct value of the MTU.
// If the file descriptor is created using a helper,
// then is the responsibility of the helper to set
// the correct MTU value.
m_mtu = mtu;
return true;
}
uint16_t
FdNetDevice::GetMtu (void) const
{
return m_mtu;
}
bool
FdNetDevice::IsLinkUp (void) const
{
return m_linkUp;
}
void
FdNetDevice::AddLinkChangeCallback (Callback<void> callback)
{
m_linkChangeCallbacks.ConnectWithoutContext (callback);
}
bool
FdNetDevice::IsBroadcast (void) const
{
return m_isBroadcast;
}
void
FdNetDevice::SetIsBroadcast (bool broadcast)
{
m_isBroadcast = broadcast;
}
Address
FdNetDevice::GetBroadcast (void) const
{
return Mac48Address ("ff:ff:ff:ff:ff:ff");
}
bool
FdNetDevice::IsMulticast (void) const
{
return m_isMulticast;
}
void
FdNetDevice::SetIsMulticast (bool multicast)
{
m_isMulticast = multicast;
}
Address
FdNetDevice::GetMulticast (Ipv4Address multicastGroup) const
{
return Mac48Address::GetMulticast (multicastGroup);
}
Address
FdNetDevice::GetMulticast (Ipv6Address addr) const
{
return Mac48Address::GetMulticast (addr);
}
bool
FdNetDevice::IsBridge (void) const
{
return false;
}
bool
FdNetDevice::IsPointToPoint (void) const
{
return false;
}
Ptr<Node>
FdNetDevice::GetNode (void) const
{
return m_node;
}
void
FdNetDevice::SetNode (Ptr<Node> node)
{
m_node = node;
}
bool
FdNetDevice::NeedsArp (void) const
{
return true;
}
void
FdNetDevice::SetReceiveCallback (NetDevice::ReceiveCallback cb)
{
m_rxCallback = cb;
}
void
FdNetDevice::SetPromiscReceiveCallback (PromiscReceiveCallback cb)
{
m_promiscRxCallback = cb;
}
bool
FdNetDevice::SupportsSendFrom (void) const
{
return true;
}
} // namespace ns3

View File

@@ -0,0 +1,462 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2012 INRIA, 2012 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
*
* Author: Alina Quereilhac <alina.quereilhac@inria.fr>
* Claudio Freire <klaussfreire@sourceforge.net>
*/
#ifndef FD_NET_DEVICE_H
#define FD_NET_DEVICE_H
#include "ns3/address.h"
#include "ns3/callback.h"
#include "ns3/data-rate.h"
#include "ns3/event-id.h"
#include "ns3/mac48-address.h"
#include "ns3/net-device.h"
#include "ns3/node.h"
#include "ns3/packet.h"
#include "ns3/ptr.h"
#include "ns3/system-condition.h"
#include "ns3/traced-callback.h"
#include "ns3/unix-fd-reader.h"
#include "ns3/system-mutex.h"
#include <string.h>
namespace ns3 {
class FdNetDeviceFdReader : public FdReader
{
public:
/**
* Constructor for the FdNetDevice.
*/
FdNetDeviceFdReader ();
/**
* Set size of the read buffer.
*
*/
void SetBufferSize (uint32_t bufferSize);
private:
FdReader::Data DoRead (void);
uint32_t m_bufferSize;
};
class Node;
/**
* \defgroup fd-net-device FdNetDevice
* This section documents the API of the ns-3 fd-net-device module.
* For a generic functional description, please refer to the ns-3 manual.
*/
/**
* \ingroup fd-net-device
*
* \brief a NetDevice to read/write network traffic from/into a file descriptor.
*
* A FdNetDevice object will read and write frames/packets from/to a file descriptor.
* This file descriptor might be associated to a Linux TAP/TUN device, to a socket
* or to a user space process, allowing the simulation to exchange traffic with the
* "outside-world"
*
*/
class FdNetDevice : public NetDevice
{
public:
static TypeId GetTypeId (void);
/**
* Enumeration of the types of frames supported in the class.
*/
enum EncapsulationMode
{
DIX, /**< DIX II / Ethernet II packet */
LLC, /**< 802.2 LLC/SNAP Packet*/
DIXPI, /**< When using TAP devices, if flag
IFF_NO_PI is not set on the device,
IP packets will have an extra header:
Flags [2 bytes]
Proto [2 bytes]
Raw protocol(IP, IPv6, etc) frame. */
};
/**
* Constructor for the FdNetDevice.
*/
FdNetDevice ();
/**
* Destructor for the FdNetDevice.
*/
virtual ~FdNetDevice ();
/**
* Set the link layer encapsulation mode of this device.
*
* \param mode The link layer encapsulation mode of this device.
*
*/
void SetEncapsulationMode (FdNetDevice::EncapsulationMode mode);
/**
* Get the link layer encapsulation mode of this device.
*
* \returns The link layer encapsulation mode of this device.
*/
FdNetDevice::EncapsulationMode GetEncapsulationMode (void) const;
/**
* Set the associated file descriptor.
*
*/
void SetFileDescriptor (int fd);
/**
* 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);
// inherited from NetDevice base class.
virtual void SetIfIndex (const uint32_t index);
virtual uint32_t GetIfIndex (void) const;
virtual Ptr<Channel> GetChannel (void) const;
virtual void SetAddress (Address address);
virtual Address GetAddress (void) const;
virtual bool SetMtu (const uint16_t mtu);
virtual uint16_t GetMtu (void) const;
virtual bool IsLinkUp (void) const;
virtual void AddLinkChangeCallback (Callback<void> callback);
virtual bool IsBroadcast (void) const;
virtual Address GetBroadcast (void) const;
virtual bool IsMulticast (void) const;
virtual Address GetMulticast (Ipv4Address multicastGroup) const;
virtual bool IsPointToPoint (void) const;
virtual bool IsBridge (void) const;
virtual bool Send (Ptr<Packet> packet, const Address& dest, uint16_t protocolNumber);
virtual bool SendFrom (Ptr<Packet> packet, const Address& source, const Address& dest, uint16_t protocolNumber);
virtual Ptr<Node> GetNode (void) const;
virtual void SetNode (Ptr<Node> node);
virtual bool NeedsArp (void) const;
virtual void SetReceiveCallback (NetDevice::ReceiveCallback cb);
virtual void SetPromiscReceiveCallback (NetDevice::PromiscReceiveCallback cb);
virtual bool SupportsSendFrom () const;
virtual Address GetMulticast (Ipv6Address addr) const;
virtual void SetIsBroadcast (bool broadcast);
virtual void SetIsMulticast (bool multicast);
protected:
virtual void DoDispose (void);
private:
// private copy constructor as sugested in:
// http://www.nsnam.org/wiki/index.php/NS-3_Python_Bindings#.22invalid_use_of_incomplete_type.22
FdNetDevice (FdNetDevice const &);
/**
* \internal
*
* Spin up the device
*/
void StartDevice (void);
/**
* \internal
*
* Tear down the device
*/
void StopDevice (void);
/**
* \internal
*
* Callback to invoke when a new frame is received
*/
void ReceiveCallback (uint8_t *buf, ssize_t len);
/**
* \internal
*
* Forward the frame to the appropriate callback for processing
*/
void ForwardUp (uint8_t *buf, ssize_t len);
/**
* 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);
/**
* \internal
*
* The ns-3 node associated to the net device.
*/
Ptr<Node> m_node;
/*
* \internal
*
* 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;
/**
* \internal
*
* The ns-3 interface index (in the sense of net device index) that has been assigned to this network device.
*/
uint32_t m_ifIndex;
/**
* \internal
*
* The MTU associated to the file descriptor technology
*/
uint16_t m_mtu;
/**
* \internal
*
* The file descriptor used for receive/send network traffic.
*/
int m_fd;
/**
* \internal
*
* Reader for the file descriptor.
*/
Ptr<FdNetDeviceFdReader> m_fdReader;
/**
* \internal
*
* The net device mac address.
*/
Mac48Address m_address;
/**
* \internal
*
* The typ of encapsulation of the received/transmited frames.
*/
EncapsulationMode m_encapMode;
/**
* \internal
*
* 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;
/**
* \internal
*
* Callbacks to fire if the link changes state (up or down).
*/
TracedCallback<> m_linkChangeCallbacks;
/**
* \internal
*
* Flag indicating whether or not the underlying net device supports
* broadcast.
*/
bool m_isBroadcast;
/**
* \internal
*
* Flag indicating whether or not the underlying net device supports
* multicast.
*/
bool m_isMulticast;
/**
* \internal
*
* Number of packets that were received and scheduled for read but not yeat read.
*/
uint32_t m_pendingReadCount;
/**
* \internal
*
* Maximum number of packets that can be received and scheduled for read but not yeat read.
*/
uint32_t m_maxPendingReads;
/**
* \internal
*
* Mutex to increase pending read counter.
*/
SystemMutex m_pendingReadMutex;
/**
* \internal
*
* Time to start spinning up the device
*/
Time m_tStart;
/**
* \internal
*
* Time to start tearing down the device
*/
Time m_tStop;
EventId m_startEvent;
EventId m_stopEvent;
/**
* 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 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 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 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;
};
} // namespace ns3
#endif /* FD_NET_DEVICE_H */

View File

@@ -0,0 +1,22 @@
#! /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 = [
("dummy-network", "True", "True"),
("fd-emu-ping", "False", "True"),
("fd-emu-udp-echo", "False", "True"),
("fd-tap-ping", "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.

1
src/fd-net-device/waf vendored Normal file
View File

@@ -0,0 +1 @@
exec "`dirname "$0"`"/../../../waf "$@"

123
src/fd-net-device/wscript Normal file
View File

@@ -0,0 +1,123 @@
## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
import os.path
def configure(conf):
conf.env['ENABLE_FDNETDEV'] = False
if conf.env['ENABLE_THREADING']:
have_sysioctl = conf.check_nonfatal(header_name='sys/ioctl.h',
define_name = 'HAVE_SYS_IOCTL_H')
have_netif = conf.check_nonfatal(header_name='net/if.h',
define_name = 'HAVE_IF_NETS_H')
# Enable use of TUN/TAP helper
conf.env['ENABLE_TAP'] = conf.check_nonfatal(
header_name='linux/if_tun.h',
define_name='HAVE_IF_TUN_H') and have_sysioctl and have_netif
if conf.env['ENABLE_TAP']:
conf.define('HAVE_TAP_CREATOR', 1)
# Enable use of raw socket (EMU) helper.
conf.env['ENABLE_EMU'] = conf.check_nonfatal(
header_name='netpacket/packet.h',
define_name='HAVE_PACKET_H') and have_sysioctl and have_netif
if conf.env['ENABLE_EMU']:
conf.define('HAVE_RAW_SOCKET_CREATOR', 1)
# Enable use of PlanetLab TAP helper
# TODO: How to validate
(sysname, nodename, release, version, machine) = os.uname()
if release.find('onelab') != -1:
conf.env['ENABLE_PLANETLAB'] = True
conf.define('HAVE_PLANETLAB_TAP_CREATOR', 1)
# Enable the FdNetDevice module.
# Our only requirement is threading support.
conf.env['ENABLE_FDNETDEV'] = True
conf.report_optional_feature("FdNetDevice",
"File Descriptor Net Device",
True,
"FdNetDevice module enabled")
else:
conf.report_optional_feature("FdNetDevice",
"File Descriptor Net Device",
False,
"needs threading support which is not available")
if conf.env['ENABLE_FDNETDEV']:
blddir = os.path.abspath(os.path.join(conf.bldnode.abspath(), conf.variant))
dir = os.path.abspath(os.path.join(blddir, "src/fd-net-device"))
conf.env.append_value('NS3_EXECUTABLE_PATH', dir)
else:
# Add this module to the list of modules that won't be built
# if they are enabled.
conf.env['MODULES_NOT_BUILT'].append('fd-net-device')
def build(bld):
# Don't do anything for this module if emu's not enabled.
if not bld.env['ENABLE_FDNETDEV']:
return
module = bld.create_ns3_module('fd-net-device', ['network'])
module.source = [
'model/fd-net-device.cc',
'helper/fd-net-device-helper.cc',
'helper/tap-fd-net-device-helper.cc',
'helper/emu-fd-net-device-helper.cc',
'helper/planetlab-fd-net-device-helper.cc',
'helper/encode-decode.cc',
'helper/creator-utils.cc',
]
headers = bld.new_task_gen(features=['ns3header'])
headers.module = 'fd-net-device'
headers.source = [
'model/fd-net-device.h',
'helper/fd-net-device-helper.h',
'helper/tap-fd-net-device-helper.h',
'helper/emu-fd-net-device-helper.h',
'helper/planetlab-fd-net-device-helper.h',
]
if bld.env['ENABLE_TAP']:
if not bld.env['PLATFORM'].startswith('freebsd'):
creator = bld.create_suid_program('tap-creator')
creator.source = [
'helper/tap-creator.cc',
'helper/encode-decode.cc',
'helper/creator-utils.cc',
]
module.env.append_value("DEFINES",
"TAP_CREATOR=\"%s\"" % (creator.target,))
if bld.env['ENABLE_EMU']:
creator = bld.create_suid_program('raw-sock-creator')
creator.source = [
'helper/raw-sock-creator.cc',
'helper/encode-decode.cc',
'helper/creator-utils.cc',
]
module.env.append_value("DEFINES",
"RAW_SOCK_CREATOR=\"%s\"" % (creator.target,))
if bld.env['ENABLE_PLANETLAB']:
creator = bld.create_suid_program('planetlab-tap-creator')
creator.source = [
'helper/planetlab-tap-creator.cc',
'helper/encode-decode.cc',
'helper/creator-utils.cc',
]
module.env.append_value("DEFINES",
"PLANETLAB_TAP_CREATOR=\"%s\"" % (creator.target,))
if bld.env['ENABLE_EXAMPLES']:
bld.add_subdirs('examples')
bld.ns3_python_bindings()