Merge fd-net-device into ns-3-dev
This commit is contained in:
7
src/fd-net-device/bindings/callbacks_list.py
Normal file
7
src/fd-net-device/bindings/callbacks_list.py
Normal 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'],
|
||||
]
|
||||
4574
src/fd-net-device/bindings/modulegen__gcc_ILP32.py
Normal file
4574
src/fd-net-device/bindings/modulegen__gcc_ILP32.py
Normal file
File diff suppressed because it is too large
Load Diff
4574
src/fd-net-device/bindings/modulegen__gcc_LP64.py
Normal file
4574
src/fd-net-device/bindings/modulegen__gcc_LP64.py
Normal file
File diff suppressed because it is too large
Load Diff
12
src/fd-net-device/bindings/modulegen_customizations.py
Normal file
12
src/fd-net-device/bindings/modulegen_customizations.py
Normal 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'])
|
||||
|
||||
81
src/fd-net-device/examples/dummy-network.cc
Normal file
81
src/fd-net-device/examples/dummy-network.cc
Normal 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 ();
|
||||
}
|
||||
196
src/fd-net-device/examples/fd-emu-onoff.cc
Normal file
196
src/fd-net-device/examples/fd-emu-onoff.cc
Normal 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;
|
||||
}
|
||||
|
||||
222
src/fd-net-device/examples/fd-emu-ping.cc
Normal file
222
src/fd-net-device/examples/fd-emu-ping.cc
Normal 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.");
|
||||
}
|
||||
166
src/fd-net-device/examples/fd-emu-udp-echo.cc
Normal file
166
src/fd-net-device/examples/fd-emu-udp-echo.cc
Normal 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.");
|
||||
}
|
||||
213
src/fd-net-device/examples/fd-planetlab-ping.cc
Normal file
213
src/fd-net-device/examples/fd-planetlab-ping.cc
Normal 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.");
|
||||
}
|
||||
216
src/fd-net-device/examples/fd-tap-ping.cc
Normal file
216
src/fd-net-device/examples/fd-tap-ping.cc
Normal 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.");
|
||||
}
|
||||
164
src/fd-net-device/examples/fd-tap-ping6.cc
Normal file
164
src/fd-net-device/examples/fd-tap-ping6.cc
Normal 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.");
|
||||
}
|
||||
127
src/fd-net-device/examples/fd2fd-onoff.cc
Normal file
127
src/fd-net-device/examples/fd2fd-onoff.cc
Normal 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
1
src/fd-net-device/examples/waf
vendored
Normal file
@@ -0,0 +1 @@
|
||||
exec "`dirname "$0"`"/../../waf "$@"
|
||||
28
src/fd-net-device/examples/wscript
Normal file
28
src/fd-net-device/examples/wscript
Normal 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'
|
||||
|
||||
176
src/fd-net-device/helper/creator-utils.cc
Normal file
176
src/fd-net-device/helper/creator-utils.cc
Normal 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
|
||||
70
src/fd-net-device/helper/creator-utils.h
Normal file
70
src/fd-net-device/helper/creator-utils.h
Normal 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 */
|
||||
|
||||
419
src/fd-net-device/helper/emu-fd-net-device-helper.cc
Normal file
419
src/fd-net-device/helper/emu-fd-net-device-helper.cc
Normal 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
|
||||
91
src/fd-net-device/helper/emu-fd-net-device-helper.h
Normal file
91
src/fd-net-device/helper/emu-fd-net-device-helper.h
Normal 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 */
|
||||
111
src/fd-net-device/helper/encode-decode.cc
Normal file
111
src/fd-net-device/helper/encode-decode.cc
Normal 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
|
||||
33
src/fd-net-device/helper/encode-decode.h
Normal file
33
src/fd-net-device/helper/encode-decode.h
Normal 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 */
|
||||
|
||||
204
src/fd-net-device/helper/fd-net-device-helper.cc
Normal file
204
src/fd-net-device/helper/fd-net-device-helper.cc
Normal 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
|
||||
134
src/fd-net-device/helper/fd-net-device-helper.h
Normal file
134
src/fd-net-device/helper/fd-net-device-helper.h
Normal 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 */
|
||||
343
src/fd-net-device/helper/planetlab-fd-net-device-helper.cc
Normal file
343
src/fd-net-device/helper/planetlab-fd-net-device-helper.cc
Normal 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
|
||||
|
||||
|
||||
103
src/fd-net-device/helper/planetlab-fd-net-device-helper.h
Normal file
103
src/fd-net-device/helper/planetlab-fd-net-device-helper.h
Normal 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 */
|
||||
235
src/fd-net-device/helper/planetlab-tap-creator.cc
Normal file
235
src/fd-net-device/helper/planetlab-tap-creator.cc
Normal 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;
|
||||
}
|
||||
95
src/fd-net-device/helper/raw-sock-creator.cc
Normal file
95
src/fd-net-device/helper/raw-sock-creator.cc
Normal 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;
|
||||
}
|
||||
|
||||
426
src/fd-net-device/helper/tap-creator.cc
Normal file
426
src/fd-net-device/helper/tap-creator.cc
Normal 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;
|
||||
}
|
||||
414
src/fd-net-device/helper/tap-fd-net-device-helper.cc
Normal file
414
src/fd-net-device/helper/tap-fd-net-device-helper.cc
Normal 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
|
||||
|
||||
|
||||
159
src/fd-net-device/helper/tap-fd-net-device-helper.h
Normal file
159
src/fd-net-device/helper/tap-fd-net-device-helper.h
Normal 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 */
|
||||
718
src/fd-net-device/model/fd-net-device.cc
Normal file
718
src/fd-net-device/model/fd-net-device.cc
Normal 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
|
||||
462
src/fd-net-device/model/fd-net-device.h
Normal file
462
src/fd-net-device/model/fd-net-device.h
Normal 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 */
|
||||
|
||||
22
src/fd-net-device/test/examples-to-run.py
Normal file
22
src/fd-net-device/test/examples-to-run.py
Normal 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
1
src/fd-net-device/waf
vendored
Normal file
@@ -0,0 +1 @@
|
||||
exec "`dirname "$0"`"/../../../waf "$@"
|
||||
123
src/fd-net-device/wscript
Normal file
123
src/fd-net-device/wscript
Normal 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()
|
||||
|
||||
Reference in New Issue
Block a user