--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/tap-wifi-dumbbell.cc Fri Feb 13 00:10:21 2009 -0500
@@ -0,0 +1,210 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+// Network topology
+//
+// +----------+
+// | external |
+// | Linux |
+// | Host |
+// | "left" |
+// +----------+
+// | n0 n3 n4
+// | +--------+ +------------+ +------------+
+// +-------| tap | | | | |
+// | bridge | ... | | | |
+// +--------+ +------------+ +------------+
+// | Wifi | | Wifi | P2P |-----| P2P | CSMA |
+// +--------+ +------+-----+ +-----+------+
+// | | ^ |
+// ((*)) ((*)) | |
+// P2P 10.1.2 |
+// ((*)) ((*)) | n5 n6 n7
+// | | | | | |
+// n1 n2 ================
+// Wifi 10.1.1 CSMA LAN 10.1.3
+//
+// The Wifi device on node zero is: 10.1.1.1
+// The Wifi device on node one is: 10.1.1.2
+// The Wifi device on node two is: 10.1.1.3
+// The Wifi device on node three is: 10.1.1.4
+// The P2P device on node three is: 10.1.2.1
+// The P2P device on node four is: 10.1.2.2
+// The CSMA device on node four is: 10.1.3.1
+// The CSMA device on node five is: 10.1.3.2
+// The CSMA device on node six is: 10.1.3.3
+// The CSMA device on node seven is: 10.1.3.4
+//
+// Some simple things to do:
+//
+// 1) Ping one of the simulated nodes on the left side of the topology.
+//
+// ./waf --run tap-wifi-dumbbell&
+// ping 10.1.1.3
+//
+// 2) Configure a route in the linux host and ping once of the nodes on the
+// right, across the point-to-point link. You will see relatively large
+// delays due to CBR background traffic on the point-to-point (see next
+// item).
+//
+// ./waf --run tap-wifi-dumbbell&
+// sudo route add -net 10.1.3.0 netmask 255.255.255.0 dev left gw 10.1.1.2
+// ping 10.1.3.4
+//
+// Take a look at the pcap traces and note that the timing reflects the
+// addition of the significant delay and low bandwidth configured on the
+// point-to-point link along with the high traffic.
+//
+// 3) Fiddle with the background CBR traffic across the point-to-point
+// link and watch the ping timing change. The OnOffApplication "DataRate"
+// attribute defaults to 500kb/s and the "PacketSize" Attribute defaults
+// to 512. The point-to-point "DataRate" is set to 512kb/s in the script,
+// so in the default case, the link is pretty full. This should be
+// reflected in large delays seen by ping. You can crank down the CBR
+// traffic data rate and watch the ping timing change dramatically.
+//
+// ./waf --run "tap-wifi-dumbbell --ns3::OnOffApplication::DataRate=100kb/s"&
+// sudo route add -net 10.1.3.0 netmask 255.255.255.0 dev left gw 10.1.1.2
+// ping 10.1.3.4
+//
+
+#include <iostream>
+#include <fstream>
+
+#include "ns3/simulator-module.h"
+#include "ns3/node-module.h"
+#include "ns3/core-module.h"
+#include "ns3/wifi-module.h"
+#include "ns3/helper-module.h"
+#include "ns3/global-routing-module.h"
+
+using namespace ns3;
+
+NS_LOG_COMPONENT_DEFINE ("TapDumbbellExample");
+
+int
+main (int argc, char *argv[])
+{
+ RandomVariable::UseGlobalSeed (1, 1, 2, 3, 5, 8);
+
+ CommandLine cmd;
+ cmd.Parse (argc, argv);
+
+ GlobalValue::Bind ("SimulatorImplementationType", StringValue ("ns3::RealtimeSimulatorImpl"));
+
+ Config::SetDefault ("ns3::Ipv4L3Protocol::CalcChecksum", BooleanValue (true));
+ Config::SetDefault ("ns3::Icmpv4L4Protocol::CalcChecksum", BooleanValue (true));
+ Config::SetDefault ("ns3::TcpL4Protocol::CalcChecksum", BooleanValue (true));
+ Config::SetDefault ("ns3::UdpL4Protocol::CalcChecksum", BooleanValue (true));
+
+ //
+ // The topology has a Wifi network of four nodes on the left side. We'll make
+ // node zero the AP and have the other three will be the STAs.
+ //
+ NodeContainer nodesLeft;
+ nodesLeft.Create (4);
+
+ YansWifiPhyHelper wifiPhy = YansWifiPhyHelper::Default ();
+ YansWifiChannelHelper wifiChannel = YansWifiChannelHelper::Default ();
+ wifiPhy.SetChannel (wifiChannel.Create ());
+
+ Ssid ssid = Ssid ("left");
+ WifiHelper wifi = WifiHelper::Default ();
+ wifi.SetRemoteStationManager ("ns3::ArfWifiManager");
+
+ wifi.SetMac ("ns3::NqapWifiMac",
+ "Ssid", SsidValue (ssid),
+ "BeaconGeneration", BooleanValue (true),
+ "BeaconInterval", TimeValue (Seconds (2.5)));
+ NetDeviceContainer devicesLeft = wifi.Install (wifiPhy, nodesLeft.Get (0));
+
+
+ wifi.SetMac ("ns3::NqstaWifiMac",
+ "Ssid", SsidValue (ssid),
+ "ActiveProbing", BooleanValue (false));
+ devicesLeft.Add (wifi.Install (wifiPhy, NodeContainer (nodesLeft.Get (1), nodesLeft.Get (2), nodesLeft.Get (3))));
+
+ MobilityHelper mobility;
+ mobility.Install (nodesLeft);
+
+ InternetStackHelper internetLeft;
+ internetLeft.Install (nodesLeft);
+
+ Ipv4AddressHelper ipv4Left;
+ ipv4Left.SetBase ("10.1.1.0", "255.255.255.0");
+ Ipv4InterfaceContainer interfacesLeft = ipv4Left.Assign (devicesLeft);
+
+ TapBridgeHelper bridgeLeft (interfacesLeft.GetAddress (1));
+ bridgeLeft.SetAttribute ("DeviceName", StringValue ("left"));
+ bridgeLeft.Install (nodesLeft.Get (0), devicesLeft.Get (0));
+
+ //
+ // Now, create the right side.
+ //
+ NodeContainer nodesRight;
+ nodesRight.Create (4);
+
+ CsmaHelper csmaRight;
+ csmaRight.SetChannelAttribute ("DataRate", DataRateValue (5000000));
+ csmaRight.SetChannelAttribute ("Delay", TimeValue (MilliSeconds (2)));
+
+ NetDeviceContainer devicesRight = csmaRight.Install (nodesRight);
+
+ InternetStackHelper internetRight;
+ internetRight.Install (nodesRight);
+
+ Ipv4AddressHelper ipv4Right;
+ ipv4Right.SetBase ("10.1.3.0", "255.255.255.0");
+ Ipv4InterfaceContainer interfacesRight = ipv4Right.Assign (devicesRight);
+
+ //
+ // Stick in the point-to-point line between the sides.
+ //
+ PointToPointHelper p2p;
+ p2p.SetDeviceAttribute ("DataRate", StringValue ("512kbps"));
+ p2p.SetChannelAttribute ("Delay", StringValue ("10ms"));
+
+ NodeContainer nodes = NodeContainer (nodesLeft.Get(3), nodesRight.Get (0));
+ NetDeviceContainer devices = p2p.Install (nodes);
+
+ Ipv4AddressHelper ipv4;
+ ipv4.SetBase ("10.1.2.0", "255.255.255.192");
+ Ipv4InterfaceContainer interfaces = ipv4.Assign (devices);
+
+ //
+ // Simulate some CBR traffic over the point-to-point link
+ //
+ uint16_t port = 9; // Discard port (RFC 863)
+ OnOffHelper onoff ("ns3::UdpSocketFactory", InetSocketAddress (interfaces.GetAddress (1), port));
+ onoff.SetAttribute ("OnTime", RandomVariableValue (ConstantVariable (1)));
+ onoff.SetAttribute ("OffTime", RandomVariableValue (ConstantVariable (0)));
+
+ ApplicationContainer apps = onoff.Install (nodesLeft.Get (3));
+ apps.Start (Seconds (1.0));
+
+ // Create a packet sink to receive these packets
+ PacketSinkHelper sink ("ns3::UdpSocketFactory", InetSocketAddress (Ipv4Address::GetAny (), port));
+
+ apps = sink.Install (nodesRight.Get (0));
+ apps.Start (Seconds (1.0));
+
+ CsmaHelper::EnablePcapAll ("tap-dumbbell");
+ GlobalRouteManager::PopulateRoutingTables ();
+
+ Simulator::Stop (Seconds (60.));
+ Simulator::Run ();
+ Simulator::Destroy ();
+}
--- a/examples/wscript Thu Feb 12 16:49:58 2009 -0500
+++ b/examples/wscript Fri Feb 13 00:10:21 2009 -0500
@@ -145,3 +145,7 @@
['emu', 'internet-stack'])
obj.source = 'emu-udp-echo.cc'
+ if env['ENABLE_TAP']:
+ obj = bld.create_ns3_program('tap-wifi-dumbbell',
+ ['wifi', 'csma', 'point-to-point', 'tap-bridge', 'internet-stack'])
+ obj.source = 'tap-wifi-dumbbell.cc'
--- a/src/devices/csma/csma-net-device.cc Thu Feb 12 16:49:58 2009 -0500
+++ b/src/devices/csma/csma-net-device.cc Fri Feb 13 00:10:21 2009 -0500
@@ -656,27 +656,22 @@
}
else
{
+ uint16_t protocol;
//
- // variable <protocol> must be initialized to avoid a compiler warning in the RAW case that breaks the optimized build.
+ // 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.
//
- uint16_t protocol = 0;
-
- switch (m_encapMode)
+ if (header.GetLengthType () <= 1500)
{
- case DIX:
+ LlcSnapHeader llc;
+ packet->RemoveHeader (llc);
+ protocol = llc.GetType ();
+ }
+ else
+ {
protocol = header.GetLengthType ();
- break;
- case LLC:
- {
- LlcSnapHeader llc;
- packet->RemoveHeader (llc);
- protocol = llc.GetType ();
- }
- break;
- case ILLEGAL:
- default:
- NS_FATAL_ERROR ("CsmaNetDevice::Receive(): Unknown packet encapsulation mode");
- break;
}
PacketType packetType;
--- a/src/devices/emu/wscript Thu Feb 12 16:49:58 2009 -0500
+++ b/src/devices/emu/wscript Fri Feb 13 00:10:21 2009 -0500
@@ -2,11 +2,11 @@
def configure(conf):
if conf.env['ENABLE_THREADING']:
- conf.env['ENABLE_EMU'] = conf.check(header_name='linux/if_ether.h',
- define_name='HAVE_IF_ETHER_H')
+ conf.env['ENABLE_EMU'] = conf.check(header_name='netpacket/packet.h',
+ define_name='HAVE_PACKET_H')
conf.report_optional_feature("EmuNetDevice", "Emulated Net Device",
conf.env['ENABLE_EMU'],
- "<linux/if_ether.h> include not detected")
+ "<netpacket/packet.h> include not detected")
else:
conf.report_optional_feature("EmuNetDevice", "Emulated Net Device",
False,
--- a/src/devices/point-to-point/ppp-header.cc Thu Feb 12 16:49:58 2009 -0500
+++ b/src/devices/point-to-point/ppp-header.cc Fri Feb 13 00:10:21 2009 -0500
@@ -17,6 +17,7 @@
*/
#include <iostream>
+#include "ns3/abort.h"
#include "ns3/assert.h"
#include "ns3/log.h"
#include "ns3/header.h"
@@ -73,9 +74,8 @@
uint32_t
PppHeader::Deserialize (Buffer::Iterator start)
{
- uint16_t __attribute__((unused))data = start.ReadNtohU16 ();
- NS_ASSERT_MSG (data == 0x0021, "MyHeader::Deserialize(): "
- "expected protocol 0x0021");
+ uint16_t data = start.ReadNtohU16 ();
+ NS_ABORT_MSG_UNLESS (data == 0x0021, "MyHeader::Deserialize(): expected protocol 0x0021");
return 2;
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/tap-bridge/tap-bridge.cc Fri Feb 13 00:10:21 2009 -0500
@@ -0,0 +1,976 @@
+/* -*- 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 "tap-bridge.h"
+#include "tap-encode-decode.h"
+
+#include "ns3/node.h"
+#include "ns3/channel.h"
+#include "ns3/packet.h"
+#include "ns3/ethernet-header.h"
+#include "ns3/llc-snap-header.h"
+#include "ns3/log.h"
+#include "ns3/abort.h"
+#include "ns3/boolean.h"
+#include "ns3/string.h"
+#include "ns3/ipv4.h"
+#include "ns3/simulator.h"
+#include "ns3/realtime-simulator-impl.h"
+#include "ns3/system-thread.h"
+
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <errno.h>
+#include <limits>
+#include <stdlib.h>
+
+//
+// Sometimes having a tap-creator is actually more trouble than solution. In
+// these cases you can uncomment the define of TAP_CREATOR below and the
+// simulation will just use a device you have preconfigured. This is useful
+// if you are running in an environment where you have got to run as root,
+// such as ORBIT or CORE.
+//
+// sudo tunctl -t tap0
+// sudo ifconfig tap0 hw ether 00:00:00:00:00:01
+// sudo ifconfig tap0 10.1.1.1 netmask 255.255.255.0 up
+//
+
+// #define NO_CREATOR
+
+#ifdef NO_CREATOR
+#include <fcntl.h>
+#include <net/if.h>
+#include <linux/if_tun.h>
+#include <sys/ioctl.h>
+#endif
+
+NS_LOG_COMPONENT_DEFINE ("TapBridge");
+
+namespace ns3 {
+
+#define TAP_MAGIC 95549
+
+NS_OBJECT_ENSURE_REGISTERED (TapBridge);
+
+TypeId
+TapBridge::GetTypeId (void)
+{
+ static TypeId tid = TypeId ("ns3::TapBridge")
+ .SetParent<NetDevice> ()
+ .AddConstructor<TapBridge> ()
+ .AddAttribute ("DeviceName",
+ "The name of the tap device to create.",
+ StringValue (""),
+ MakeStringAccessor (&TapBridge::m_tapDeviceName),
+ MakeStringChecker ())
+ .AddAttribute ("Gateway",
+ "The IP address of the default gateway to assign to the tap device.",
+ Ipv4AddressValue ("255.255.255.255"),
+ MakeIpv4AddressAccessor (&TapBridge::m_tapGateway),
+ MakeIpv4AddressChecker ())
+ .AddAttribute ("IpAddress",
+ "The IP address to assign to the tap device.",
+ Ipv4AddressValue ("255.255.255.255"),
+ MakeIpv4AddressAccessor (&TapBridge::m_tapIp),
+ MakeIpv4AddressChecker ())
+ .AddAttribute ("MacAddress",
+ "The MAC address to assign to the tap device.",
+ Mac48AddressValue (Mac48Address ("ff:ff:ff:ff:ff:ff")),
+ MakeMac48AddressAccessor (&TapBridge::m_tapMac),
+ MakeMac48AddressChecker ())
+ .AddAttribute ("Netmask",
+ "The network mask to assign to the tap device.",
+ Ipv4MaskValue ("255.255.255.255"),
+ MakeIpv4MaskAccessor (&TapBridge::m_tapNetmask),
+ MakeIpv4MaskChecker ())
+ .AddAttribute ("Start",
+ "The simulation time at which to spin up the tap device read thread.",
+ TimeValue (Seconds (0.)),
+ MakeTimeAccessor (&TapBridge::m_tStart),
+ MakeTimeChecker ())
+ .AddAttribute ("Stop",
+ "The simulation time at which to tear down the tap device read thread.",
+ TimeValue (Seconds (0.)),
+ MakeTimeAccessor (&TapBridge::m_tStop),
+ MakeTimeChecker ())
+ ;
+ return tid;
+}
+
+TapBridge::TapBridge ()
+: m_node (0),
+ m_ifIndex (0),
+ m_mtu (0),
+ m_sock (-1),
+ m_startEvent (),
+ m_stopEvent (),
+ m_readThread (0)
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ Start (m_tStart);
+}
+
+TapBridge::~TapBridge()
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ m_bridgedDevice = 0;
+}
+
+ void
+TapBridge::DoDispose ()
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ NetDevice::DoDispose ();
+}
+
+void
+TapBridge::Start (Time tStart)
+{
+ NS_LOG_FUNCTION (tStart);
+
+ //
+ // Cancel any pending start event and schedule a new one at some relative time in the future.
+ //
+ Simulator::Cancel (m_startEvent);
+ m_startEvent = Simulator::Schedule (tStart, &TapBridge::StartTapDevice, this);
+}
+
+ void
+TapBridge::Stop (Time tStop)
+{
+ NS_LOG_FUNCTION (tStop);
+ //
+ // Cancel any pending stop event and schedule a new one at some relative time in the future.
+ //
+ Simulator::Cancel (m_stopEvent);
+ m_startEvent = Simulator::Schedule (tStop, &TapBridge::StopTapDevice, this);
+}
+
+ void
+TapBridge::StartTapDevice (void)
+{
+ NS_LOG_FUNCTION_NOARGS ();
+
+ NS_ABORT_MSG_IF (m_sock != -1, "TapBridge::StartTapDevice(): Tap is already started");
+
+ //
+ // Spin up the tap bridge and start receiving packets.
+ //
+ NS_LOG_LOGIC ("Creating tap device");
+
+ //
+ // Call out to a separate process running as suid root in order to get the
+ // tap device allocated and set up. We do this to avoid having the entire
+ // simulation running as root. If this method returns, we'll have a socket
+ // waiting for us in m_sock that we can use to talk to the newly created
+ // tap device.
+ //
+ CreateTap ();
+
+ //
+ // Now spin up a read thread to read packets from the tap device.
+ //
+ NS_ABORT_MSG_IF (m_readThread != 0,"TapBridge::StartTapDevice(): Receive thread is already running");
+ NS_LOG_LOGIC ("Spinning up read thread");
+
+ m_readThread = Create<SystemThread> (MakeCallback (&TapBridge::ReadThread, this));
+ m_readThread->Start ();
+}
+
+void
+TapBridge::StopTapDevice (void)
+{
+ NS_LOG_FUNCTION_NOARGS ();
+
+ close (m_sock);
+ m_sock = -1;
+
+ NS_ASSERT_MSG (m_readThread != 0, "TapBridge::StopTapDevice(): Receive thread is not running");
+
+ NS_LOG_LOGIC ("Joining read thread");
+ m_readThread->Join ();
+ m_readThread = 0;
+}
+
+void
+TapBridge::CreateTap (void)
+{
+ NS_LOG_FUNCTION_NOARGS ();
+
+#ifdef NO_CREATOR
+ //
+ // In come cases, can you say FreeBSD, the tap-creator just gets in the way.
+ // in this case, just define NO_CREATOR, manually set up your tap device and
+ // just open and use it.
+ //
+ //
+ // Creation and management of Tap devices is done via the tun device
+ //
+ m_sock = open ("/dev/net/tun", O_RDWR);
+ NS_ABORT_MSG_IF (m_sock == -1, "TapBridge::CreateTap(): could not open /dev/net/tun: " << strerror (errno));
+
+ //
+ // Allocate a tap device, making sure that it will not send the tun_pi header.
+ // If we provide a null name to the ifr.ifr_name, we tell the kernel to pick
+ // a name for us (i.e., tapn where n = 0..255
+ //
+ struct ifreq ifr;
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+ strcpy (ifr.ifr_name, m_tapDeviceName.c_str ());
+ int status = ioctl (m_sock, TUNSETIFF, (void *) &ifr);
+ NS_ABORT_MSG_IF (status == -1, "TapBridge::CreateTap(): could not open device " << m_tapDeviceName <<
+ ": " << strerror (errno));
+
+#else // use the tap-creator
+
+ //
+ // We want to create a tap device on the host. 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 do what it takes to create the
+ // tap. 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);
+ NS_ABORT_MSG_IF (sock == -1, "TapBridge::CreateTap(): 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, "TapBridge::CreateTap(): 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, "TapBridge::CreateTap(): Could not getsockname(): errno = " << strerror (errno));
+
+ //
+ // Now encode that socket name (family and path) as a string of hex digits
+ //
+ std::string path = TapBufferToString((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 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;
+ // -g<gateway-address> The IP address to use as the default gateway;
+ // -i<IP-address> The IP address to assign to the new tap device;
+ // -m<MAC-address> The MAC-48 address to assign to the new tap device;
+ // -n<network-mask> The network mask to assign to the new tap device;
+ // -p<path> the path to the unix socket described above.
+ //
+ // Example tap-creator -dnewdev -g1.2.3.2 -i1.2.3.1 -m08:00:2e:00:01:23 -n255.255.255.0 -pblah
+ //
+ // We want to get as much of this stuff automagically as possible.
+ //
+ // <IP-address> is the IP address we are going to set in the newly
+ // created Tap device on the Linux host. At the point in the simulation
+ // where devices are coming up, we should have all of our IP addresses
+ // assigned. That means that we can find the IP address to assign to
+ // the new Tap device from the IP address associated with the bridged
+ // net device.
+ //
+ Ptr<NetDevice> nd = GetBridgedNetDevice ();
+ Ptr<Node> n = nd->GetNode ();
+ Ptr<Ipv4> ipv4 = n->GetObject<Ipv4> ();
+ uint32_t index = ipv4->FindInterfaceForDevice (nd);
+ Ipv4Address ipv4Address = ipv4->GetAddress (index);
+
+ //
+ // The net mask is sitting right there next to the ipv4 address.
+ //
+ Ipv4Mask ipv4Mask = ipv4->GetNetworkMask (index);
+
+ //
+ // The MAC address should also already be assigned and waiting for us in
+ // the bridged net device.
+ //
+ Address address = nd->GetAddress ();
+ Mac48Address mac48Address = Mac48Address::ConvertFrom (address);
+
+ //
+ // 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;
+ ossDeviceName << "-d" << m_tapDeviceName;
+
+ //
+ // The gateway-address is something we can't derive, so we rely on it
+ // being configured via an Attribute through the helper.
+ //
+ std::ostringstream ossGateway;
+ ossGateway << "-g" << m_tapGateway;
+
+ //
+ // For flexibility, we do allow a client to override any of the values
+ // above via attributes, so only use our found values if the Attribute
+ // is not equal to its default value (empty string or broadcast address).
+ //
+ std::ostringstream ossIp;
+ if (m_tapIp.IsBroadcast ())
+ {
+ ossIp << "-i" << ipv4Address;
+ }
+ else
+ {
+ ossIp << "-i" << m_tapIp;
+ }
+
+ std::ostringstream ossMac;
+ if (m_tapMac.IsBroadcast ())
+ {
+ ossMac << "-m" << mac48Address;
+ }
+ else
+ {
+ ossMac << "-m" << m_tapMac;
+ }
+
+ std::ostringstream ossNetmask;
+ if (m_tapNetmask.IsEqual (Ipv4Mask::GetOnes ()))
+ {
+ ossNetmask << "-n" << ipv4Mask;
+ }
+ else
+ {
+ ossNetmask << "-n" << m_tapNetmask;
+ }
+
+ std::ostringstream ossPath;
+ ossPath << "-p" << path;
+ //
+ // Execute the socket creation process image.
+ //
+ status = ::execl (FindCreator ("tap-creator").c_str (),
+ FindCreator ("tap-creator").c_str (), // argv[0] (filename)
+ ossDeviceName.str ().c_str (), // argv[1] (-d<device name>)
+ ossGateway.str ().c_str (), // argv[2] (-g<gateway>)
+ ossIp.str ().c_str (), // argv[3] (-i<IP address>)
+ ossMac.str ().c_str (), // argv[4] (-m<MAC address>)
+ ossNetmask.str ().c_str (), // argv[5] (-n<net mask>)
+ ossPath.str ().c_str (), // argv[6] (-p<path>)
+ (char *)NULL);
+
+ //
+ // If the execl successfully completes, it never returns. If it returns it failed or the OS is
+ // broken. In either case, we bail.
+ //
+ NS_FATAL_ERROR ("TapBridge::CreateTap(): Back from execl(), 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, "TapBridge::CreateTap(): waitpid() fails, errno = " << strerror (errno));
+ NS_ASSERT_MSG (pid == waited, "TapBridge::CreateTap(): 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,
+ "TapBridge::CreateTap(): socket creator exited normally with status " << exitStatus);
+ }
+ else
+ {
+ NS_FATAL_ERROR ("TapBridge::CreateTap(): 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.
+ //
+ ssize_t bytesRead = recvmsg (sock, &msg, 0);
+ NS_ABORT_MSG_IF (bytesRead != sizeof(int), "TapBridge::CreateTap(): 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 == 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);
+ m_sock = *rawSocket;
+ return;
+ }
+ 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");
+ }
+#endif // use the tap-creator
+}
+
+std::string
+TapBridge::FindCreator (std::string creatorName)
+{
+ NS_LOG_FUNCTION (creatorName);
+
+ std::list<std::string> locations;
+
+ // in repo
+ locations.push_back ("./build/optimized/src/devices/tap-bridge/");
+ locations.push_back ("./build/debug/src/devices/tap-bridge/");
+
+ // in src
+ locations.push_back ("../build/optimized/src/devices/tap-bridge/");
+ locations.push_back ("../build/debug/src/devices/tap-bridge/");
+
+ // in src/devices
+ locations.push_back ("../../build/optimized/src/devices/tap-bridge/");
+ locations.push_back ("../../build/debug/src/devices/tap-bridge/");
+
+ // in src/devices/tap-bridge
+ locations.push_back ("../../../build/optimized/src/devices/tap-bridge/");
+ locations.push_back ("../../../build/debug/src/devices/tap-bridge/");
+
+ for (std::list<std::string>::const_iterator i = locations.begin (); i != locations.end (); ++i)
+ {
+ struct stat st;
+
+ if (::stat ((*i + creatorName).c_str (), &st) == 0)
+ {
+ NS_LOG_INFO ("Found Creator " << *i + creatorName);
+ return *i + creatorName;
+ }
+ }
+
+ NS_FATAL_ERROR ("TapBridge::FindCreator(): Couldn't find creator");
+ return ""; // quiet compiler
+}
+
+void
+TapBridge::ReadThread (void)
+{
+ NS_LOG_FUNCTION_NOARGS ();
+
+ //
+ // It's important to remember that we're in a completely different thread than the simulator is running in. We
+ // need to synchronize with that other thread to get the packet up into ns-3. What we will need to do is to schedule
+ // a method to deal with the packet using the multithreaded simulator we are most certainly running. However, I just
+ // said it -- we are talking about two threads here, so it is very, very dangerous to do any kind of reference couning
+ // on a shared object. Just don't do it. So what we're going to do is to allocate a buffer on the heap and pass that
+ // buffer into the ns-3 context thread where it will create the packet.
+ //
+ int32_t len = -1;
+
+ for (;;)
+ {
+ uint32_t bufferSize = 65536;
+ uint8_t *buf = (uint8_t *)malloc (bufferSize);
+ NS_ABORT_MSG_IF (buf == 0, "TapBridge::ReadThread(): malloc packet buffer failed");
+ NS_LOG_LOGIC ("Calling read on tap device socket fd");
+ len = read (m_sock, buf, bufferSize);
+
+ if (len == -1)
+ {
+ free (buf);
+ buf = 0;
+ return;
+ }
+
+ NS_LOG_INFO ("TapBridge::ReadThread(): Received packet");
+ NS_LOG_INFO ("TapBridge::ReadThread(): Scheduling handler");
+ DynamicCast<RealtimeSimulatorImpl> (Simulator::GetImplementation ())->ScheduleRealtimeNow (
+ MakeEvent (&TapBridge::ForwardToBridgedDevice, this, buf, len));
+ buf = 0;
+ }
+}
+
+void
+TapBridge::ForwardToBridgedDevice (uint8_t *buf, uint32_t len)
+{
+ NS_LOG_FUNCTION (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;
+
+ //
+ // Make sure the packet we received is reasonable enough for the rest of the
+ // system to handle and get it ready to be injected directly into an ns-3
+ // device. What should come back is a packet with the Ethernet header
+ // (and possibly an LLC header as well) stripped off.
+ //
+ Address src, dst;
+ uint16_t type;
+
+ NS_LOG_LOGIC ("Received packet from tap device");
+
+ Ptr<Packet> p = Filter (packet, &src, &dst, &type);
+ if (p == 0)
+ {
+ NS_LOG_LOGIC ("Discarding packet as unfit for ns-3 consumption");
+ return;
+ }
+
+ NS_LOG_LOGIC ("Pkt source is " << src);
+ NS_LOG_LOGIC ("Pkt destination is " << dst);
+ NS_LOG_LOGIC ("Pkt LengthType is " << type);
+
+ NS_LOG_LOGIC ("Forwarding packet");
+ m_bridgedDevice->Send (packet, dst, type);
+}
+
+Ptr<Packet>
+TapBridge::Filter (Ptr<Packet> p, Address *src, Address *dst, uint16_t *type)
+{
+ NS_LOG_FUNCTION (p);
+ uint32_t pktSize;
+
+ //
+ // We have a candidate packet for injection into ns-3. We expect that since
+ // it came over a socket that provides Ethernet packets, it sould be big
+ // enough to hold an EthernetHeader. If it can't, we signify the packet
+ // should be filtered out by returning 0.
+ //
+ pktSize = p->GetSize ();
+ EthernetHeader header (false);
+ if (pktSize < header.GetSerializedSize ())
+ {
+ return 0;
+ }
+
+ p->RemoveHeader (header);
+
+ NS_LOG_LOGIC ("Pkt source is " << header.GetSource ());
+ NS_LOG_LOGIC ("Pkt destination is " << header.GetDestination ());
+ NS_LOG_LOGIC ("Pkt LengthType is " << 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 (header.GetLengthType () <= 1500)
+ {
+ *src = header.GetSource ();
+ *dst = header.GetDestination ();
+
+ pktSize = p->GetSize ();
+ LlcSnapHeader llc;
+ if (pktSize < llc.GetSerializedSize ())
+ {
+ return 0;
+ }
+
+ p->RemoveHeader (llc);
+ *type = llc.GetType ();
+ }
+ else
+ {
+ *src = header.GetSource ();
+ *dst = header.GetDestination ();
+ *type = header.GetLengthType ();
+ }
+
+ //
+ // What we give back is a packet without the Ethernet header (nor the
+ // possible llc/snap header) on it. We think it is ready to send on
+ // out the bridged net device.
+ //
+ return p;
+}
+
+Ptr<NetDevice>
+TapBridge::GetBridgedNetDevice (void)
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ return m_bridgedDevice;
+}
+
+void
+TapBridge::SetBridgedNetDevice (Ptr<NetDevice> bridgedDevice)
+{
+ NS_LOG_FUNCTION (bridgedDevice);
+
+ NS_ASSERT_MSG (m_node != 0, "TapBridge::SetBridgedDevice: Bridge not installed in a node");
+ NS_ASSERT_MSG (bridgedDevice != this, "TapBridge::SetBridgedDevice: Cannot bridge to self");
+ NS_ASSERT_MSG (m_bridgedDevice == 0, "TapBridge::SetBridgedDevice: Already bridged");
+
+ if (!Mac48Address::IsMatchingType (bridgedDevice->GetAddress ()))
+ {
+ NS_FATAL_ERROR ("TapBridge::SetBridgedDevice: Device does not support eui 48 addresses: cannot be added to bridge.");
+ }
+
+ if (!bridgedDevice->SupportsSendFrom ())
+ {
+ NS_FATAL_ERROR ("TapBridge::SetBridgedDevice: Device does not support SendFrom: cannot be added to bridge.");
+ }
+
+ //
+ // Tell the bridged device to forward its received packets here. We use the
+ // promiscuous mode hook to get both the source and destination addresses.
+ //
+ m_node->RegisterProtocolHandler (MakeCallback (&TapBridge::ReceiveFromBridgedDevice, this), 0, bridgedDevice, true);
+ m_bridgedDevice = bridgedDevice;
+}
+
+void
+TapBridge::ReceiveFromBridgedDevice (
+ Ptr<NetDevice> device,
+ Ptr<const Packet> packet,
+ uint16_t protocol,
+ Address const &src,
+ Address const &dst,
+ PacketType packetType)
+{
+ NS_LOG_FUNCTION (device << packet << protocol << src << dst << packetType);
+ NS_ASSERT_MSG (device == m_bridgedDevice, "TapBridge::SetBridgedDevice: Received packet from unexpected device");
+
+ NS_LOG_DEBUG ("Packet UID is " << packet->GetUid ());
+
+ Mac48Address from = Mac48Address::ConvertFrom (src);
+ Mac48Address to = Mac48Address::ConvertFrom (dst);
+
+ //
+ // We hooked the promiscuous mode protocol handler so we could get the
+ // destination address of the actual packet. This means we will be getting
+ // PACKET_OTHERHOST packets (not broadcast, not multicast, not unicast to
+ // this device, but to some other address). We don't want to forward those
+ // PACKET_OTHERHOST packets so just ignore them
+ //
+ if (packetType == PACKET_OTHERHOST)
+ {
+ return;
+ }
+
+ //
+ // We have received a packet from the ns-3 net device that has been associated
+ // with this bridge. We want to take these bits and send them off to the
+ // Tap device on the Linux host. Once we do this, the bits in the packet will
+ // percolate up through the stack on the Linux host.
+ //
+ // The ns-3 net device that is the source of these bits has removed the MAC
+ // header, so we have to put one back on.
+ //
+ Ptr<Packet> p = packet->Copy ();
+
+ EthernetHeader header = EthernetHeader (false);
+ header.SetSource (from);
+ header.SetDestination (to);
+ header.SetLengthType (protocol);
+ p->AddHeader (header);
+
+ NS_LOG_LOGIC ("Writing packet to Linux host");
+ NS_LOG_LOGIC ("Pkt source is " << header.GetSource ());
+ NS_LOG_LOGIC ("Pkt destination is " << header.GetDestination ());
+ NS_LOG_LOGIC ("Pkt LengthType is " << header.GetLengthType ());
+ NS_LOG_LOGIC ("Pkt size is " << p->GetSize ());
+
+ uint32_t bytesWritten = write (m_sock, p->PeekData (), p->GetSize ());
+ NS_ABORT_MSG_IF (bytesWritten != p->GetSize (), "TapBridge::ReceiveFromBridgedDevice(): Write error.");
+}
+
+void
+TapBridge::SetName(const std::string name)
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ m_name = name;
+}
+
+std::string
+TapBridge::GetName(void) const
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ return m_name;
+}
+
+void
+TapBridge::SetIfIndex(const uint32_t index)
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ m_ifIndex = index;
+}
+
+uint32_t
+TapBridge::GetIfIndex(void) const
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ return m_ifIndex;
+}
+
+Ptr<Channel>
+TapBridge::GetChannel (void) const
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ return 0;
+}
+
+Address
+TapBridge::GetAddress (void) const
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ return m_address;
+}
+
+bool
+TapBridge::SetMtu (const uint16_t mtu)
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ m_mtu = mtu;
+ return true;
+}
+
+uint16_t
+TapBridge::GetMtu (void) const
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ return m_mtu;
+}
+
+
+bool
+TapBridge::IsLinkUp (void) const
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ return true;
+}
+
+void
+TapBridge::SetLinkChangeCallback (Callback<void> callback)
+{
+ NS_LOG_FUNCTION_NOARGS ();
+}
+
+bool
+TapBridge::IsBroadcast (void) const
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ return true;
+}
+
+Address
+TapBridge::GetBroadcast (void) const
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ return Mac48Address ("ff:ff:ff:ff:ff:ff");
+}
+
+bool
+TapBridge::IsMulticast (void) const
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ return true;
+}
+
+Address
+TapBridge::GetMulticast (Ipv4Address multicastGroup) const
+{
+ NS_LOG_FUNCTION (this << multicastGroup);
+ Mac48Address multicast = Mac48Address::GetMulticast (multicastGroup);
+ return multicast;
+}
+
+bool
+TapBridge::IsPointToPoint (void) const
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ return false;
+}
+
+bool
+TapBridge::IsBridge (void) const
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ //
+ // Returning false from IsBridge in a device called TapBridge may seem odd
+ // at first glance, but this test is for a device that bridges ns-3 devices
+ // together. The Tap bridge doesn't do that -- it bridges an ns-3 device to
+ // a Linux device. This is a completely different story.
+ //
+ return false;
+}
+
+bool
+TapBridge::Send (Ptr<Packet> packet, const Address& dst, uint16_t protocol)
+{
+ NS_LOG_FUNCTION (packet << dst << protocol);
+ NS_FATAL_ERROR ("TapBridge::Send: You may not call Send on a TapBridge directly");
+ return false;
+}
+
+bool
+TapBridge::SendFrom (Ptr<Packet> packet, const Address& src, const Address& dst, uint16_t protocol)
+{
+ NS_LOG_FUNCTION (packet << src << dst << protocol);
+ NS_FATAL_ERROR ("TapBridge::Send: You may not call SendFrom on a TapBridge directly");
+ return false;
+}
+
+Ptr<Node>
+TapBridge::GetNode (void) const
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ return m_node;
+}
+
+void
+TapBridge::SetNode (Ptr<Node> node)
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ m_node = node;
+}
+
+bool
+TapBridge::NeedsArp (void) const
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ return true;
+}
+
+void
+TapBridge::SetReceiveCallback (NetDevice::ReceiveCallback cb)
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ m_rxCallback = cb;
+}
+
+void
+TapBridge::SetPromiscReceiveCallback (NetDevice::PromiscReceiveCallback cb)
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ m_promiscRxCallback = cb;
+}
+
+bool
+TapBridge::SupportsSendFrom () const
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ return true;
+}
+
+Address TapBridge::GetMulticast (Ipv6Address addr) const
+{
+ NS_LOG_FUNCTION (this << addr);
+ return Mac48Address::GetMulticast (addr);
+}
+
+} // namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/tap-bridge/tap-bridge.h Fri Feb 13 00:10:21 2009 -0500
@@ -0,0 +1,410 @@
+/* -*- 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
+ */
+
+#ifndef TAP_BRIDGE_H
+#define TAP_BRIDGE_H
+
+#include <string.h>
+#include "ns3/address.h"
+#include "ns3/net-device.h"
+#include "ns3/node.h"
+#include "ns3/callback.h"
+#include "ns3/packet.h"
+#include "ns3/traced-callback.h"
+#include "ns3/event-id.h"
+#include "ns3/nstime.h"
+#include "ns3/data-rate.h"
+#include "ns3/ptr.h"
+#include "ns3/mac48-address.h"
+#include "ns3/system-thread.h"
+
+namespace ns3 {
+
+class Node;
+
+/**
+ * \ingroup devices
+ * \defgroup tap-bridge TapBridge
+ *
+ * \brief A bridge to make it appear that a host is connected to an ns-3 net device.
+ *
+ * The Tap Bridge lives in a kind of a gray world somewhere between a Linux host and
+ * an ns-3 bridge device. From the Linux perspective, this code appears as the user
+ * mode handler for a Tap net device. That is, when the Linux host writes to the
+ * /dev/tap device that we create for it, the write is redirected into the TapBridge
+ * and from that perspective, becomes a read. The TapBridge then redirects the data
+ * written (by the Linux host) to the tap device on out the ns-3 net device to which
+ * we are bridged. When a packet comes in from the ns-3 world to the ns-3 net device
+ * we are bridging, it appears via a callback from that net device. Our job is to
+ * take those bits and write them back to the host using the user mode handler for
+ * /dev/tapx. This write to the device will then appear to the Linux host as if a
+ * packet has arrived on its device.
+ *
+ * The upshot is that the Tap Bridge appears to bridge a tap device on a Linux host
+ * in the "real world" to an ns-3 net device in the simulation. In order to do this
+ * we need a "ghost node" in the simulation to hold the bridged ns-3 net device and
+ * this Tap Bridge. This node will not be able to actually do anything else in the
+ * simulation with respect to the Tap Bridge and its bridged net device. This is
+ * because:
+ *
+ * - Bits sent to the Tap Bridge using its Send() method are completely ignored.
+ * The Tap Bridge is not, itself, connected to any network.
+ * - The bridged ns-3 net device is has had its receive callback disconnected from
+ * the ns-3 node and reconnected to the Tap Bridge. All data received by a
+ * bridged device will be sent to the Linux host and will not be received by the
+ * node. You can send but you cannot ever receive.
+ *
+ * You will be able to perform typical ns-3 operations on the ghost node if you so
+ * desire. The internet stack, for example, must be there and functional on that
+ * node in order to participate in IP address assignment and global routing.
+ * However, interfaces talking any Tap Bridge or associated bridged net devices
+ * will not work completely. If you understand exactly what you are doing, you
+ * can set up other interfaces and devices on the ghost node and use them; but we
+ * generally recommend that you treat this node as a ghost of the Linux host and
+ * leave it alone.
+ */
+
+/**
+ * \ingroup tap-bridge
+ * \brief A bridge to make it appear that a host is connected to an ns-3 net device.
+ */
+
+class TapBridge : public NetDevice
+{
+public:
+ static TypeId GetTypeId (void);
+
+ TapBridge ();
+ virtual ~TapBridge ();
+
+ /** \brief Get the bridged net device.
+ *
+ * The bridged net device is the ns-3 device to which this bridge is connected,
+ *
+ * \returns the bridged net device.
+ */
+ Ptr<NetDevice> GetBridgedNetDevice (void);
+
+ /** \brief Set the ns-3 net device to bridge.
+ *
+ * This method tells the bridge which ns-3 net device it should use to connect
+ * the simulation side of the bridge.
+ *
+ * \attention The ns-3 net device that is being set as the device must have an
+ * an IP address assigned to it before the simulation is run. This address
+ * will be used to set the hardware address of the host Linux device.
+ */
+ void SetBridgedNetDevice (Ptr<NetDevice> bridgedDevice);
+
+ /**
+ * \brief Set a start time for the device.
+ *
+ * The tap bridge consumes a non-trivial amount of time to start. It starts
+ * up in the context of a scheduled event to ensure that all configuration
+ * has been completed before extracting the configuration (IP addresses, etc.)
+ * In order to allow a more reasonable start-up sequence than a thundering
+ * herd of devices, the time at which each device starts is also configurable
+ * bot via the Attribute system and via this call.
+ *
+ * \param tStart the start time
+ */
+ void Start (Time tStart);
+
+ /**
+ * Set a stop time for the device.
+ *
+ * @param tStop the stop time
+ *
+ * \see TapBridge::Start
+ */
+ void Stop (Time tStop);
+
+ //
+ // The following methods are inherited from NetDevice base class and are
+ // documented there.
+ //
+ virtual void SetName(const std::string name);
+ virtual std::string GetName(void) const;
+ virtual void SetIfIndex(const uint32_t index);
+ virtual uint32_t GetIfIndex(void) const;
+ virtual Ptr<Channel> GetChannel (void) const;
+ 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 SetLinkChangeCallback (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;
+
+protected:
+ /**
+ * \internal
+ *
+ * Call out to a separate process running as suid root in order to get our
+ * tap device created. We do this to avoid having the entire simulation
+ * running as root. If this method returns, we'll have a socket waiting
+ * for us in m_sock that we can use to talk to the tap device.
+ */
+ virtual void DoDispose (void);
+
+ void ReceiveFromBridgedDevice (Ptr<NetDevice> device, Ptr<const Packet> packet, uint16_t protocol,
+ Address const &src, Address const &dst, PacketType packetType);
+private:
+
+ /**
+ * \internal
+ *
+ * Call out to a separate process running as suid root in order to get our
+ * tap device created. We do this to avoid having the entire simulation
+ * running as root. If this method returns, we'll have a socket waiting
+ * for us in m_sock that we can use to talk to the tap device.
+ */
+ void CreateTap (void);
+
+ /**
+ * \internal
+ *
+ * Figure out where the tap creation program lives on the system.
+ *
+ * \param creatorName The name of the program used to create the Tap.
+ * \returns A path name to use when you want to create a Tap.
+ */
+ std::string FindCreator (std::string creatorName);
+
+ /**
+ * \internal
+ *
+ * Spin up the device
+ */
+ void StartTapDevice (void);
+
+ /**
+ * \internal
+ *
+ * Tear down the device
+ */
+ void StopTapDevice (void);
+
+ /**
+ * \internal
+ *
+ * Loop to read and process packets
+ */
+ void ReadThread (void);
+
+ /*
+ * \internal
+ *
+ * Forward a packet received from the tap device to the bridged ns-3
+ * device
+ *
+ * \param buf A character buffer containing the actaul packet bits that were
+ * received from the host.
+ * \param buf The length of the buffer.
+ */
+ void ForwardToBridgedDevice (uint8_t *buf, uint32_t len);
+
+ /**
+ * \internal
+ *
+ * The host we are bridged to is in the evil real world. Do some sanity
+ * checking on a received packet to make sure it isn't too evil for our
+ * poor naive virginal simulator to handle.
+ *
+ * \param packet The packet we received from the host, and which we need
+ * to check.
+ * \param src A pointer to the data structure that will get the source
+ * MAC address of the packet (extracted from the packet Ethernet
+ * header).
+ * \param dst A pointer to the data structure that will get the destination
+ * MAC address of the packet (extracted from the packet Ethernet
+ * header).
+ * \param type A pointer to the variable that will get the packet type from
+ * either the Ethernet header in the case of type interpretation
+ * (DIX framing) or from the 802.2 LLC header in the case of
+ * length interpretation (802.3 framing).
+ */
+ Ptr<Packet> Filter (Ptr<Packet> packet, Address *src, Address *dst, uint16_t *type);
+
+ /**
+ * \internal
+ *
+ * Callback used to hook the standard packet receive callback of the TapBridge
+ * ns-3 net device. This is never called, and therefore no packets will ever
+ * be received forwarded up the IP stack on the ghost node through this device.
+ */
+ NetDevice::ReceiveCallback m_rxCallback;
+
+ /**
+ * \internal
+ *
+ * Callback used to hook the promiscuous packet receive callback of the TapBridge
+ * ns-3 net device. This is never called, and therefore no packets will ever
+ * be received forwarded up the IP stack on the ghost node through this device.
+ *
+ * Note that we intercept the similar callback in the bridged device in order to
+ * do the actual bridging between the bridged ns-3 net device and the Tap device
+ * on the host.
+ */
+ NetDevice::PromiscReceiveCallback m_promiscRxCallback;
+
+ /**
+ * \internal
+ *
+ * Pointer to the (ghost) Node to which we are connected.
+ */
+ Ptr<Node> m_node;
+
+ /**
+ * \internal
+ *
+ * A possible name for the (ghost) Node to which we are connected.
+ */
+ std::string m_name;
+
+ /**
+ * \internal
+ *
+ * The ns-3 interface index of this TapBridge net device.
+ */
+ uint32_t m_ifIndex;
+
+ /**
+ * \internal
+ *
+ * The common mtu to use for the net devices
+ */
+ uint16_t m_mtu;
+
+ /**
+ * \internal
+ *
+ * The socket (actually interpreted as fd) to use to talk to the Tap device on
+ * the real internet host.
+ */
+ int32_t m_sock;
+
+ /**
+ * \internal
+ *
+ * The ID of the ns-3 event used to schedule the start up of the underlying
+ * host Tap device and ns-3 read thread.
+ */
+ EventId m_startEvent;
+
+ /**
+ * \internal
+ *
+ * The ID of the ns-3 event used to schedule the tear down of the underlying
+ * host Tap device and ns-3 read thread.
+ */
+ EventId m_stopEvent;
+
+ /**
+ * \internal
+ *
+ * Used to identify the ns-3 read thread used to do blocking reads on the
+ * socket (fd) corresponding to the host device.
+ */
+ Ptr<SystemThread> m_readThread;
+
+ /**
+ * \internal
+ *
+ * The (unused) MAC address of the TapBridge net device. Since the TapBridge
+ * is implemented as a ns-3 net device, it is required to implement certain
+ * functionality. In this case, the TapBridge is automatically assigned a
+ * MAC address, but it is not used. The MAC address assigned to the internet
+ * host actually comes from the bridged (N.B. the "ed") device and not from
+ * the bridge device.
+ */
+ Mac48Address m_address;
+
+ /**
+ * \internal
+ *
+ * Time to start spinning up the device
+ */
+ Time m_tStart;
+
+ /**
+ * \internal
+ *
+ * Time to start tearing down the device
+ */
+ Time m_tStop;
+
+ /**
+ * \internal
+ *
+ * The name of the device to create on the host. If the device name is the
+ * empty string, we allow the host kernel to choose a name.
+ */
+ std::string m_tapDeviceName;
+
+ /**
+ * \internal
+ *
+ * The IP address to use as the device default gateway on the host.
+ */
+ Ipv4Address m_tapGateway;
+
+ /**
+ * \internal
+ *
+ * The IP address to use as the device IP on the host.
+ */
+ Ipv4Address m_tapIp;
+ /**
+ * \internal
+ *
+ * The MAC address to use as the hardware address on the host.
+ */
+ Mac48Address m_tapMac;
+
+ /**
+ * \internal
+ *
+ * The network mask to assign to the device created on the host.
+ */
+ Ipv4Mask m_tapNetmask;
+
+ /**
+ * \internal
+ *
+ * The ns-3 net device to which we are bridging.
+ */
+ Ptr<NetDevice> m_bridgedDevice;
+};
+
+} // namespace ns3
+
+#endif /* TAP_BRIDGE_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/tap-bridge/tap-creator.cc Fri Feb 13 00:10:21 2009 -0500
@@ -0,0 +1,456 @@
+/* -*- 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 <unistd.h>
+#include <stdint.h>
+#include <string>
+#include <string.h> // for strerror
+#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>
+#if 0
+#include <linux/un.h>
+#include <linux/if.h>
+#include <linux/if_tun.h>
+#include <linux/route.h>
+#else
+#include <sys/un.h>
+#include <net/if.h>
+#include <linux/if_tun.h>
+#include <net/route.h>
+#endif
+#include <netinet/in.h>
+
+#include "tap-encode-decode.h"
+
+#define TAP_MAGIC 95549
+
+static int gVerbose = 0; // Set to true to turn on logging messages.
+
+#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); \
+ }
+
+//
+// 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)
+
+static 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;
+ }
+}
+
+static uint32_t
+AsciiToIpv4 (const char *address)
+{
+ uint32_t host = 0;
+ while (true) {
+ uint8_t byte = 0;
+ while (*address != ASCII_DOT &&
+ *address != 0) {
+ byte *= 10;
+ byte += *address - ASCII_ZERO;
+ address++;
+ }
+ host <<= 8;
+ host |= byte;
+ if (*address == 0) {
+ break;
+ }
+ address++;
+ }
+ return host;
+}
+
+static 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++;
+ }
+}
+
+static void
+SetInetAddress (sockaddr *ad, uint32_t networkOrder)
+{
+ struct sockaddr_in *sin = (struct sockaddr_in*)ad;
+ sin->sin_family = AF_INET;
+ sin->sin_port = 0; // unused
+ sin->sin_addr.s_addr = htonl (networkOrder);
+}
+
+ static void
+SendSocket (const char *path, int fd)
+{
+ //
+ // Open a Unix (local interprocess) socket to call back to the tap bridge
+ //
+ 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 tap bridge created. It used a forward encoding
+ // method (TapBufferToString) to take the sockaddr_un it made and passed
+ // the resulting string to us. So we need to take the inverse method
+ // (TapStringToBuffer) and build the same sockaddr_un over here.
+ //
+ socklen_t clientAddrLen;
+ struct sockaddr_un clientAddr;
+
+ LOG ("Decode address " << path);
+ bool rc = ns3::TapStringToBuffer (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 tap bridge", 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
+ // tap bridge 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 tap bridge is talking to the tap socket
+ // creator and not some other creator process (emu, specifically)
+ //
+ // 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 tap bridge (that magic number).
+ //
+ struct iovec iov;
+ uint32_t magic = TAP_MAGIC;
+ iov.iov_base = &magic;
+ iov.iov_len = sizeof(magic);
+
+ //
+ // The CMSG macros you'll see below are used to create and access control
+ // messages (which is another name for ancillary data). The ancillary
+ // data is made up of pairs of struct cmsghdr structures and associated
+ // data arrays.
+ //
+ // First, we're going to allocate a buffer on the stack to contain our
+ // data array (that contains the socket). Sometimes you'll see this called
+ // an "ancillary element" but the msghdr uses the control message termimology
+ // so we call it "control."
+ //
+ size_t msg_size = sizeof(int);
+ char control[CMSG_SPACE(msg_size)];
+
+ //
+ // There is a msghdr that is used to minimize the number of parameters
+ // passed to sendmsg (which we will use to send our ancillary data). This
+ // structure uses terminology corresponding to control messages, so you'll
+ // see msg_control, which is the pointer to the ancillary data and controllen
+ // which is the size of the ancillary data array.
+ //
+ // So, initialize the message header that describes our ancillary/control data
+ // and point it to the control message/ancillary data we just allocated space
+ // for.
+ //
+ struct msghdr msg;
+ msg.msg_name = 0;
+ msg.msg_namelen = 0;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = control;
+ msg.msg_controllen = sizeof (control);
+ msg.msg_flags = 0;
+
+ //
+ // A cmsghdr contains a length field that is the length of the header and
+ // the data. It has a cmsg_level field corresponding to the originating
+ // protocol. This takes values which are legal levels for getsockopt and
+ // setsockopt (here SOL_SOCKET). We're going to use the SCM_RIGHTS type of
+ // cmsg, that indicates that the ancillary data array contains access rights
+ // that we are sending back to the tap bridge.
+ //
+ // 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 tap bridge.
+ //
+ ssize_t len = sendmsg(sock, &msg, 0);
+ ABORT_IF (len == -1, "Could not send socket back to tap bridge", 1);
+
+ LOG ("sendmsg complete");
+}
+
+ static int
+CreateTap (const char *dev, const char *gw, const char *ip, const char *mac, const char *netmask)
+{
+ //
+ // Creation and management of Tap devices is done via the tun device
+ //
+ int tap = open ("/dev/net/tun", O_RDWR);
+ ABORT_IF (tap == -1, "Could not open /dev/net/tun", true);
+
+ //
+ // Allocate a tap device, making sure that it will not send the tun_pi header.
+ // If we provide a null name to the ifr.ifr_name, we tell the kernel to pick
+ // a name for us (i.e., tapn where n = 0..255
+ //
+ struct ifreq ifr;
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+ strcpy (ifr.ifr_name, dev);
+ int status = ioctl (tap, TUNSETIFF, (void *) &ifr);
+ ABORT_IF (status == -1, "Could not allocate tap device", true);
+
+ std::string tapDeviceName = (char *)ifr.ifr_name;
+ LOG ("Allocated TAP device " << tapDeviceName);
+
+ //
+ // Set the hardware (MAC) address of the new device
+ //
+ ifr.ifr_hwaddr.sa_family = 1; // this is ARPHRD_ETHER from if_arp.h
+ AsciiToMac48 (mac, (uint8_t*)ifr.ifr_hwaddr.sa_data);
+ status = ioctl (tap, SIOCSIFHWADDR, &ifr);
+ ABORT_IF (status == -1, "Could not set MAC address", true);
+ LOG ("Set device MAC address to " << mac);
+
+ int fd = socket (AF_INET, SOCK_DGRAM, 0);
+
+ //
+ // Bring the interface up.
+ //
+ status = ioctl (fd, SIOCGIFFLAGS, &ifr);
+ ABORT_IF (status == -1, "Could not get flags for interface", true);
+ ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
+ status = ioctl (fd, SIOCSIFFLAGS, &ifr);
+ ABORT_IF (status == -1, "Could not bring interface up", true);
+ LOG ("Device is up");
+
+ //
+ // Set the IP address of the new interface/device.
+ //
+ SetInetAddress (&ifr.ifr_addr, AsciiToIpv4 (ip));
+ status = ioctl (fd, SIOCSIFADDR, &ifr);
+ ABORT_IF (status == -1, "Could not set IP address", true);
+ LOG ("Set device IP address to " << ip);
+
+ //
+ // Set the net mask of the new interface/device
+ //
+ SetInetAddress (&ifr.ifr_netmask, AsciiToIpv4 (netmask));
+ status = ioctl (fd, SIOCSIFNETMASK, &ifr);
+ ABORT_IF (status == -1, "Could not set net mask", true);
+ LOG ("Set device Net Mask to " << netmask);
+
+ return tap;
+}
+
+ int
+main (int argc, char *argv[])
+{
+ int c;
+ char *dev = (char *)"";
+ char *gw = NULL;
+ char *ip = NULL;
+ char *mac = NULL;
+ char *netmask = NULL;
+ char *path = NULL;
+
+ opterr = 0;
+
+ while ((c = getopt (argc, argv, "vd:g:i:m:n:p:")) != -1)
+ {
+ switch (c)
+ {
+ case 'd':
+ dev = optarg; // name of the new tap device
+ break;
+ case 'g':
+ gw = optarg; // gateway address for the new device
+ break;
+ case 'i':
+ ip = optarg; // ip address of the new device
+ break;
+ case 'm':
+ mac = optarg; // mac address of the new device
+ break;
+ case 'n':
+ netmask = optarg; // net mask for the new device
+ 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 provide a gateway to the external Linux host
+ // so it can talk to the ns-3 network. This ip address is provided in
+ // gw.
+ //
+ ABORT_IF (gw == NULL, "Gateway Address is a required argument", 0);
+ LOG ("Provided Gateway Address is \"" << gw << "\"");
+
+ //
+ // 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 (ip == NULL, "IP Address is a required argument", 0);
+ LOG ("Provided IP Address is \"" << ip << "\"");
+
+ //
+ // 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 be able to assign a net mask to the tap device we are
+ // allocating. This mask is allocated in the simulation and given to
+ // the bridged device.
+ //
+ ABORT_IF (netmask == NULL, "Net Mask is a required argument", 0);
+ LOG ("Provided Net Mask is \"" << netmask << "\"");
+
+ //
+ // 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 exeucte the following code:
+ //
+ LOG ("Creating Tap");
+ int sock = CreateTap (dev, gw, ip, mac, netmask);
+ 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);
+
+ return 0;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/tap-bridge/tap-encode-decode.cc Fri Feb 13 00:10:21 2009 -0500
@@ -0,0 +1,110 @@
+/* -*- 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>
+
+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
+TapBufferToString (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
+TapStringToBuffer (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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/tap-bridge/tap-encode-decode.h Fri Feb 13 00:10:21 2009 -0500
@@ -0,0 +1,33 @@
+/* -*- 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
+ */
+
+#ifndef TAP_ENCODE_DECODE_H
+#define TAP_ENCODE_DECODE_H
+
+#include <string>
+
+namespace ns3 {
+
+ std::string TapBufferToString (uint8_t *buffer, uint32_t len);
+ bool TapStringToBuffer (std::string s, uint8_t *buffer, uint32_t *len);
+
+
+} // namespace ns3
+
+#endif // TAP_ENCODE_DECODE_H
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/tap-bridge/tap.h Fri Feb 13 00:10:21 2009 -0500
@@ -0,0 +1,68 @@
+/**
+ * \ingroup devices
+ * \defgroup TapBridgeModel Tap Bridge Model
+ *
+ * \section TapBridgeModelOverview TapBridge Model Overview
+ *
+ * The Tap Bridge is designed to integrate "real" internet hosts (or more
+ * precisely, hosts that support Tun/Tap devices) into ns-3 simulations. The
+ * goal is to make it appear to the host host node in question that it has an
+ * ns-3 net device as a local device. The concept of a "real host" is a bit
+ * slippery the "real host" may actually be virtualized using readily avialable
+ * technologies such as VMware or OpenVZ.
+ *
+ * Since we are, in essence, connecting the inputs and outputs of an ns-3 net
+ * device to the inputs and outputs of a Linux Tap net device, we call this
+ * arrangement a Tap Bridge.
+ *
+ * The TapBridge appears to the Linux host computer as a network device just
+ * like any arbitrary "eth0" or "ath0" might appear. The creation and
+ * configuration of the device is done by the ns-3 simulation, however. You
+ * should not expect to be able to configure a net device via, for example,
+ * wlanconfig. The IP addresses, MAC addresses, gateway, etc., for the given
+ * Tap device are also set up by the ns-3 simulation. If you change the
+ * or manipulate the configuration manually, you will almost certainly break
+ * the simulation.
+ *
+ * The TapBridge appears to an ns-3 simulation as a channel-less net device.
+ * This device, however, must _not_ have an IP address associated with it.
+ * Be aware that this is the inverse situation of an ns-3 BridgeNetDevice
+ * which demands that its bridge ports not have IP addresses, but allows the
+ * bridge to have an IP address.
+ *
+ * The host computer will appear in a simulation as a "ghost" node that contains
+ * pairs of net devices and Tap bridges that represent the host devices. From
+ * the perspective of a simulation, the only difference between a ghost node and
+ * another node will be the presence of the TapBridge devices that connect to
+ * the hosts. Configuration of address information and the ns-3 devices is
+ * not changed in any way. A TapBridge will pick up the addressing info from
+ * the ns-3 net device to which it is connected (its "bridged" net device) and
+ * use that information to configure the device on the real host.
+ *
+ * The end result of this is a situation where one can, for example, use the
+ * standard ping utility on a real host to ping a simulated ns-3 net device. If
+ * correct routes are added to the internet host, the routing systems in ns-3
+ * will enable correct routing of the packets across simulated ns-3 networks.
+ * For an example of this, see the example program, tap-dumbbell.cc in the
+ * ns-3 distribution.
+ *
+ * \section TapBridgeChannelModel Tap Bridge Channel Model
+ *
+ * There is no channel model associated with the Tap Bridge. In fact, the
+ * intention is make it appear that the real internet host is connected to
+ * the channel of the bridged net device.
+ *
+ * \section TapBridgeTracingModel Tap Bridge Tracing Model
+ *
+ * Unlike most ns-3 devices, the TapBridge does not provide any standard trace
+ * sources. This is because the bridge is an intermediary that is essentially
+ * one function call away from the bridged device. We expect that the trace
+ * hooks in the bridged device will be sufficient for most users,
+ *
+ * \section TapBridgeUsage Using the Tap Bridge
+ *
+ * We expect that most users will interact with the TapBridge device through
+ * the TapBridgeHelper. Users of other helper classes, such as CSMA or Wifi,
+ * should be comfortable with the idioms used.
+ */
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/tap-bridge/waf Fri Feb 13 00:10:21 2009 -0500
@@ -0,0 +1,1 @@
+exec "`dirname "$0"`"/../../../waf "$@"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/tap-bridge/wscript Fri Feb 13 00:10:21 2009 -0500
@@ -0,0 +1,43 @@
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+def configure(conf):
+ if conf.env['ENABLE_THREADING']:
+ conf.env['ENABLE_TAP'] = conf.check(header_name='linux/if_tun.h',
+ define_name='HAVE_IF_TUN_H')
+ conf.report_optional_feature("TapBridge", "Tap Bridge",
+ conf.env['ENABLE_TAP'],
+ "<linux/if_tun.h> include not detected")
+ else:
+ conf.report_optional_feature("TapBridge", "Tap Bridge",
+ False,
+ "needs threading support which is not available")
+
+def build(bld):
+ module = bld.create_ns3_module('tap-bridge', ['node'])
+ module.source = [
+ ]
+ headers = bld.new_task_gen('ns3header')
+ headers.module = 'tap-bridge'
+ headers.source = [
+ 'tap.h',
+ ]
+
+ env = bld.env_of_name('default')
+ if env['ENABLE_TAP']:
+ module.source.extend([
+ 'tap-bridge.cc',
+ 'tap-encode-decode.cc',
+ ])
+ headers.source.extend([
+ 'tap-bridge.h',
+ ])
+
+
+ if not env['PLATFORM'].startswith('freebsd'):
+ obj = bld.create_suid_program('tap-creator')
+ obj.source = [
+ 'tap-creator.cc',
+ 'tap-encode-decode.cc',
+ ]
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/helper/tap-bridge-helper.cc Fri Feb 13 00:10:21 2009 -0500
@@ -0,0 +1,55 @@
+/* -*- 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 "ns3/log.h"
+#include "ns3/node.h"
+#include "ns3/tap-bridge.h"
+#include "tap-bridge-helper.h"
+
+NS_LOG_COMPONENT_DEFINE ("TapBridgeHelper");
+
+namespace ns3 {
+
+TapBridgeHelper::TapBridgeHelper (Ipv4Address gateway)
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ m_deviceFactory.SetTypeId ("ns3::TapBridge");
+ SetAttribute ("Gateway", Ipv4AddressValue (gateway));
+}
+
+void
+TapBridgeHelper::SetAttribute (std::string n1, const AttributeValue &v1)
+{
+ NS_LOG_FUNCTION (n1 << &v1);
+ m_deviceFactory.Set (n1, v1);
+}
+
+ Ptr<NetDevice>
+TapBridgeHelper::Install (Ptr<Node> node, Ptr<NetDevice> nd)
+{
+ NS_LOG_FUNCTION (node << nd);
+ NS_LOG_LOGIC ("Install TapBridge on node " << node->GetId () << " bridging net device " << nd);
+
+ Ptr<TapBridge> bridge = m_deviceFactory.Create<TapBridge> ();
+ node->AddDevice (bridge);
+ bridge->SetBridgedNetDevice (nd);
+
+ return bridge;
+}
+
+} // namespace ns3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/helper/tap-bridge-helper.h Fri Feb 13 00:10:21 2009 -0500
@@ -0,0 +1,44 @@
+/* -*- 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
+ */
+
+#ifndef TAP_BRIDGE_HELPER_H
+#define TAP_BRIDGE_HELPER_H
+
+#include "net-device-container.h"
+#include "ns3/object-factory.h"
+#include <string>
+
+namespace ns3 {
+
+class Node;
+class AttributeValue;
+
+class TapBridgeHelper
+{
+public:
+ TapBridgeHelper (Ipv4Address gateway);
+ void SetAttribute (std::string n1, const AttributeValue &v1);
+ Ptr<NetDevice> Install (Ptr<Node> node, Ptr<NetDevice> nd);
+private:
+ ObjectFactory m_deviceFactory;
+};
+
+} // namespace ns3
+
+
+#endif /* TAP_BRIDGE_HELPER_H */
--- a/src/helper/wscript Thu Feb 12 16:49:58 2009 -0500
+++ b/src/helper/wscript Fri Feb 13 00:10:21 2009 -0500
@@ -58,4 +58,11 @@
headers.source.extend([
'emu-helper.h',
])
+ if env['ENABLE_TAP']:
+ helper.source.extend([
+ 'tap-bridge-helper.cc',
+ ])
+ headers.source.extend([
+ 'tap-bridge-helper.h',
+ ])
--- a/src/internet-stack/arp-header.cc Thu Feb 12 16:49:58 2009 -0500
+++ b/src/internet-stack/arp-header.cc Fri Feb 13 00:10:21 2009 -0500
@@ -143,18 +143,32 @@
WriteTo (i, m_macDest);
WriteTo (i, m_ipv4Dest);
}
+
uint32_t
ArpHeader::Deserialize (Buffer::Iterator start)
{
Buffer::Iterator i = start;
- i.Next (2+2);
- uint32_t hardwareAddressLen = i.ReadU8 ();
- i.Next (1);
- m_type = i.ReadNtohU16 ();
- ReadFrom (i, m_macSource, hardwareAddressLen);
- ReadFrom (i, m_ipv4Source);
- ReadFrom (i, m_macDest, hardwareAddressLen);
- ReadFrom (i, m_ipv4Dest);
+ i.Next (2); // Skip HRD
+ uint32_t protocolType = i.ReadNtohU16 (); // Read PRO
+ uint32_t hardwareAddressLen = i.ReadU8 (); // Read HLN
+ uint32_t protocolAddressLen = i.ReadU8 (); // Read PLN
+
+ //
+ // It is implicit here that we have a protocol type of 0x800 (IP).
+ // It is also implicit here that we are using Ipv4 (PLN == 4).
+ // If this isn't the case, we need to return an error since we don't want to
+ // be too fragile if we get connected to real networks.
+ //
+ if (protocolType != 0x800 || protocolAddressLen != 4)
+ {
+ return 0;
+ }
+
+ m_type = i.ReadNtohU16 (); // Read OP
+ ReadFrom (i, m_macSource, hardwareAddressLen); // Read SHA (size HLN)
+ ReadFrom (i, m_ipv4Source); // Read SPA (size PLN == 4)
+ ReadFrom (i, m_macDest, hardwareAddressLen); // Read THA (size HLN)
+ ReadFrom (i, m_ipv4Dest); // Read TPA (size PLN == 4)
return GetSerializedSize ();
}
--- a/src/internet-stack/arp-l3-protocol.cc Thu Feb 12 16:49:58 2009 -0500
+++ b/src/internet-stack/arp-l3-protocol.cc Fri Feb 13 00:10:21 2009 -0500
@@ -124,9 +124,24 @@
Ptr<Packet> packet = p->Copy ();
+ NS_LOG_LOGIC ("ARP: received packet of size "<< packet->GetSize ());
+
Ptr<ArpCache> cache = FindCache (device);
+
+ //
+ // If we're connected to a real world network, then some of the fields sizes
+ // in an ARP packet can vary in ways not seen in simulations. We need to be
+ // able to detect ARP packets with headers we don't recongnize and not process
+ // them instead of crashing. The ArpHeader will return 0 if it can't deal
+ // with the received header.
+ //
ArpHeader arp;
- packet->RemoveHeader (arp);
+ uint32_t size = packet->RemoveHeader (arp);
+ if (size == 0)
+ {
+ NS_LOG_LOGIC ("ARP: Cannot remove ARP header");
+ return;
+ }
NS_LOG_LOGIC ("ARP: received "<< (arp.IsRequest ()? "request" : "reply") <<
" node="<<m_node->GetId ()<<", got request from " <<
--- a/src/node/ipv4-address-generator.cc Thu Feb 12 16:49:58 2009 -0500
+++ b/src/node/ipv4-address-generator.cc Fri Feb 13 00:10:21 2009 -0500
@@ -17,6 +17,7 @@
*/
#include <list>
+#include "ns3/abort.h"
#include "ns3/assert.h"
#include "ns3/log.h"
#include "ns3/simulation-singleton.h"
@@ -137,17 +138,14 @@
// We're going to be playing with the actual bits in the network and mask so
// pull them out into ints.
//
- uint32_t maskBits __attribute__((unused)) = mask.Get ();
+ uint32_t maskBits = mask.Get ();
uint32_t netBits = net.Get ();
uint32_t addrBits = addr.Get ();
//
// Some quick reasonableness testing.
//
- NS_ASSERT_MSG((netBits & ~maskBits) == 0,
- "Ipv4AddressGeneratorImpl::Init (): Inconsistent network and mask");
-
- NS_ASSERT_MSG((addrBits & maskBits) == 0,
- "Ipv4AddressGeneratorImpl::Init (): Inconsistent address and mask");
+ NS_ABORT_MSG_UNLESS ((netBits & ~maskBits) == 0, "Ipv4AddressGeneratorImpl::Init (): Inconsistent network and mask");
+ NS_ABORT_MSG_UNLESS ((addrBits & maskBits) == 0, "Ipv4AddressGeneratorImpl::Init (): Inconsistent address and mask");
//
// Convert the network mask into an index into the network number table.
@@ -158,10 +156,7 @@
uint32_t index = MaskToIndex (mask);
m_netTable[index].network = netBits >> m_netTable[index].shift;
-
- NS_ASSERT_MSG (addrBits <= m_netTable[index].addrMax,
- "Ipv4AddressGeneratorImpl::Init(): Address overflow");
-
+ NS_ABORT_MSG_UNLESS (addrBits <= m_netTable[index].addrMax, "Ipv4AddressGeneratorImpl::Init(): Address overflow");
m_netTable[index].addr = addrBits;
return;
}
@@ -205,9 +200,7 @@
uint32_t index = MaskToIndex (mask);
uint32_t addrBits = addr.Get ();
- NS_ASSERT_MSG (addrBits <= m_netTable[index].addrMax,
- "Ipv4AddressGeneratorImpl::InitAddress(): Address overflow");
-
+ NS_ABORT_MSG_UNLESS (addrBits <= m_netTable[index].addrMax, "Ipv4AddressGeneratorImpl::InitAddress(): Address overflow");
m_netTable[index].addr = addrBits;
}
@@ -237,8 +230,8 @@
//
uint32_t index = MaskToIndex (mask);
- NS_ASSERT_MSG (m_netTable[index].addr <= m_netTable[index].addrMax,
- "Ipv4AddressGeneratorImpl::NextAddress(): Address overflow");
+ NS_ABORT_MSG_UNLESS (m_netTable[index].addr <= m_netTable[index].addrMax,
+ "Ipv4AddressGeneratorImpl::NextAddress(): Address overflow");
Ipv4Address addr = Ipv4Address (
(m_netTable[index].network << m_netTable[index].shift) |
@@ -260,8 +253,7 @@
uint32_t addr = address.Get ();
- NS_ASSERT_MSG (addr, "Ipv4AddressGeneratorImpl::Add(): "
- "Allocating the broadcast address is not a good idea");
+ NS_ABORT_MSG_UNLESS (addr, "Ipv4AddressGeneratorImpl::Add(): Allocating the broadcast address is not a good idea");
std::list<Entry>::iterator i;
@@ -275,12 +267,10 @@
//
if (addr >= (*i).addrLow && addr <= (*i).addrHigh)
{
- NS_LOG_LOGIC ("Ipv4AddressGeneratorImpl::Add(): "
- "Address Collision: " << Ipv4Address (addr));
+ NS_LOG_LOGIC ("Ipv4AddressGeneratorImpl::Add(): Address Collision: " << Ipv4Address (addr));
if (!m_test)
{
- NS_ASSERT_MSG (0, "Ipv4AddressGeneratorImpl::Add(): "
- "Address Collision: " << Ipv4Address (addr));
+ NS_FATAL_ERROR ("Ipv4AddressGeneratorImpl::Add(): Address Collision: " << Ipv4Address (addr));
}
return false;
}
@@ -313,9 +303,7 @@
"Address Collision: " << Ipv4Address (addr));
if (!m_test)
{
- NS_ASSERT_MSG (0,
- "Ipv4AddressGeneratorImpl::Add(): "
- "Address Collision: " << Ipv4Address (addr));
+ NS_FATAL_ERROR ("Ipv4AddressGeneratorImpl::Add(): Address Collision: " << Ipv4Address (addr));
}
return false;
}
@@ -374,10 +362,7 @@
if (maskBits & 1)
{
uint32_t index = N_BITS - i;
-
- NS_ASSERT_MSG (index > 0 && index < N_BITS,
- "Ipv4AddressGenerator::MaskToIndex(): Illegal Mask");
-
+ NS_ABORT_MSG_UNLESS (index > 0 && index < N_BITS, "Ipv4AddressGenerator::MaskToIndex(): Illegal Mask");
return index;
}
maskBits >>= 1;
--- a/src/wscript Thu Feb 12 16:49:58 2009 -0500
+++ b/src/wscript Fri Feb 13 00:10:21 2009 -0500
@@ -23,6 +23,7 @@
'devices/csma',
'devices/emu',
'devices/bridge',
+ 'devices/tap-bridge',
'applications/onoff',
'applications/packet-sink',
'applications/udp-echo',
@@ -44,16 +45,16 @@
" --run and --shell; moreover, only works in some"
" specific platforms, such as Linux and Solaris)"),
action="store_true", dest='enable_rpath', default=False)
-
+
opt.add_option('--enable-modules',
help=("Build only these modules (and dependencies)"),
dest='enable_modules')
-
def configure(conf):
conf.sub_config('core')
conf.sub_config('simulator')
conf.sub_config('devices/emu')
+ conf.sub_config('devices/tap-bridge')
conf.sub_config('contrib')
conf.sub_config('internet-stack')
--- a/wscript Thu Feb 12 16:49:58 2009 -0500
+++ b/wscript Fri Feb 13 00:10:21 2009 -0500
@@ -17,6 +17,7 @@
ccroot.USE_TOP_LEVEL = True
import Task
+import Constants
import Utils
import Build
import Configure
@@ -133,7 +134,10 @@
help=('Run a shell with an environment suitably modified to run locally built programs'),
action="store_true", default=False,
dest='shell')
-
+ opt.add_option('--enable-sudo',
+ help=('Use sudo to setup suid bits on ns3 executables.'),
+ dest='enable_sudo', action='store_true',
+ default=False)
opt.add_option('--regression',
help=("Enable regression testing; only used for the 'check' target"),
default=False, dest='regression', action="store_true")
@@ -144,10 +148,6 @@
help=('For regression testing, only run/generate the indicated regression tests, '
'specified as a comma separated list of test names'),
dest='regression_tests', type="string")
- opt.add_option('--enable-sudo',
- help=('Use sudo to setup suid bits on ns3 executables.'),
- dest='enable_sudo', action='store_true',
- default=False)
opt.add_option('--with-regression-traces',
help=('Path to the regression reference traces directory'),
default=None,
@@ -240,6 +240,8 @@
env.append_value('CXXDEFINES', 'NS3_ASSERT_ENABLE')
env.append_value('CXXDEFINES', 'NS3_LOG_ENABLE')
+ env['PLATFORM'] = sys.platform
+
if sys.platform == 'win32':
if env['COMPILER_CXX'] == 'g++':
env.append_value("LINKFLAGS", "-Wl,--enable-runtime-pseudo-reloc")
@@ -258,6 +260,18 @@
# for suid bits
conf.find_program('sudo', var='SUDO')
+ why_not_sudo = "because we like it"
+ if Options.options.enable_sudo and conf.env['SUDO']:
+ env['ENABLE_SUDO'] = True
+ else:
+ env['ENABLE_SUDO'] = False
+ if Options.options.enable_sudo:
+ why_not_sudo = "program sudo not found"
+ else:
+ why_not_sudo = "option --enable-sudo not selected"
+
+ conf.report_optional_feature("ENABLE_SUDO", "Use sudo to set suid bit", env['ENABLE_SUDO'], why_not_sudo)
+
# we cannot pull regression traces without mercurial
conf.find_program('hg', var='MERCURIAL')
@@ -276,28 +290,37 @@
class SuidBuildTask(Task.TaskBase):
"""task that makes a binary Suid
"""
- after = 'link'
+ after = 'cxx_link cc_link'
+ maxjobs = 1
def __init__(self, bld, program):
self.m_display = 'build-suid'
self.__program = program
- self.__env = bld.env ()
+ self.__env = bld.env.copy ()
super(SuidBuildTask, self).__init__()
-
- def run(self):
try:
program_obj = wutils.find_program(self.__program.target, self.__env)
except ValueError, ex:
raise Utils.WafError(str(ex))
+ program_node = program_obj.path.find_or_declare(ccroot.get_target_name(program_obj))
+ self.filename = program_node.abspath(self.__env)
- program_node = program_obj.path.find_or_declare(ccroot.get_target_name(program_obj))
- #try:
- # program_node = program_obj.path.find_or_declare(ccroot.get_target_name(program_obj))
- #except AttributeError:
- # raise Utils.WafError("%s does not appear to be a program" % (self.__program.name,))
+
+ def run(self):
+ print >> sys.stderr, 'setting suid bit on executable ' + self.filename
+ if subprocess.Popen(['sudo', 'chown', 'root', self.filename]).wait():
+ return 1
+ if subprocess.Popen(['sudo', 'chmod', 'u+s', self.filename]).wait():
+ return 1
+ return 0
- filename = program_node.abspath(self.__env)
- os.system ('sudo chown root ' + filename)
- os.system ('sudo chmod u+s ' + filename)
+ def runnable_status(self):
+ "RUN_ME SKIP_ME or ASK_LATER"
+ st = os.stat(self.filename)
+ if st.st_uid == 0:
+ return Constants.SKIP_ME
+ else:
+ return Constants.RUN_ME
+
def create_suid_program(bld, name):
program = bld.new_task_gen('cxx', 'program')
@@ -305,8 +328,10 @@
program.module_deps = list()
program.name = name
program.target = name
- if bld.env['SUDO'] and Options.options.enable_sudo:
+
+ if bld.env['ENABLE_SUDO']:
SuidBuildTask(bld, program)
+
return program
def create_ns3_program(bld, name, dependencies=('simulator',)):