--- a/src/devices/tap-bridge/tap-bridge.cc Tue Jan 27 20:26:34 2009 -0800
+++ b/src/devices/tap-bridge/tap-bridge.cc Tue Jan 27 21:22:50 2009 -0800
@@ -22,9 +22,14 @@
#include "ns3/node.h"
#include "ns3/channel.h"
#include "ns3/packet.h"
+#include "ns3/ethernet-header.h"
+#include "ns3/ethernet-trailer.h"
#include "ns3/log.h"
#include "ns3/boolean.h"
+#include "ns3/string.h"
#include "ns3/simulator.h"
+#include "ns3/realtime-simulator-impl.h"
+#include "ns3/system-thread.h"
#include <sys/wait.h>
#include <sys/stat.h>
@@ -54,17 +59,56 @@
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 ("TapGateway",
+ "The IP address of the default gateway to assign to the tap device.",
+ StringValue (""),
+ MakeStringAccessor (&TapBridge::m_tapGateway),
+ MakeStringChecker ())
+ .AddAttribute ("TapIp",
+ "The IP address to assign to the tap device.",
+ StringValue (""),
+ MakeStringAccessor (&TapBridge::m_tapIp),
+ MakeStringChecker ())
+ .AddAttribute ("TapMac",
+ "The MAC address to assign to the tap device.",
+ StringValue (""),
+ MakeStringAccessor (&TapBridge::m_tapMac),
+ MakeStringChecker ())
+ .AddAttribute ("TapNetmask",
+ "The network mask to assign to the tap device.",
+ StringValue (""),
+ MakeStringAccessor (&TapBridge::m_tapMac),
+ MakeStringChecker ())
+ .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_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()
@@ -80,6 +124,82 @@
}
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 ();
+
+ //
+ // Spin up the tap bridge and start receiving packets.
+ //
+ if (m_sock != -1)
+ {
+ NS_FATAL_ERROR ("TapBridge::StartTapDevice(): Tap is already started");
+ }
+
+ 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.
+ //
+ if (m_readThread != 0)
+ {
+ NS_FATAL_ERROR ("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 ();
@@ -321,6 +441,79 @@
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);
+ if (buf == 0)
+ {
+ NS_FATAL_ERROR ("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;
+
+ //
+ // Checksum the packet
+ //
+ EthernetTrailer trailer;
+ packet->RemoveTrailer (trailer);
+ trailer.CheckFcs (packet);
+
+ //
+ // Get rid of the MAC header
+ //
+ EthernetHeader header (false);
+ packet->RemoveHeader (header);
+
+ NS_LOG_LOGIC ("Pkt source is " << header.GetSource ());
+ NS_LOG_LOGIC ("Pkt destination is " << header.GetDestination ());
+
+ m_bridgedDevice->SendFrom (packet, header.GetSource (), header.GetDestination (), protocol);
+}
+
void
TapBridge::SetBridgedDevice (Ptr<NetDevice> bridgedDevice)
{
@@ -361,15 +554,26 @@
NS_LOG_DEBUG ("Packet UID is " << packet->GetUid ());
- Mac48Address src48 = Mac48Address::ConvertFrom (src);
- Mac48Address dst48 = Mac48Address::ConvertFrom (dst);
+ Mac48Address from = Mac48Address::ConvertFrom (src);
+ Mac48Address to = Mac48Address::ConvertFrom (dst);
//
// 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.
+ // 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.
//
- NS_LOG_LOGIC ("TapBridge::ReceiveFromDevice: Not implemented");
+ Ptr<Packet> p = packet->Copy ();
+ EthernetHeader header = EthernetHeader (false);
+ header.SetSource (from);
+ header.SetDestination (to);
+ header.SetLengthType (protocolNumber);
+ p->AddHeader (header);
+
+ write (m_sock, p->PeekData (), p->GetSize ());
}
void
--- a/src/devices/tap-bridge/tap-bridge.h Tue Jan 27 20:26:34 2009 -0800
+++ b/src/devices/tap-bridge/tap-bridge.h Tue Jan 27 21:22:50 2009 -0800
@@ -19,9 +19,19 @@
#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/nstime.h"
+#include "ns3/system-thread.h"
namespace ns3 {
@@ -77,6 +87,20 @@
*/
void SetBridgedDevice (Ptr<NetDevice> bridgedDevice);
+ /**
+ * 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 SetName(const std::string name);
virtual std::string GetName(void) const;
@@ -109,7 +133,6 @@
void ReceiveFromBridgedDevice (Ptr<NetDevice> device, Ptr<const Packet> packet, uint16_t protocol,
Address const &src, Address const &dst, PacketType packetType);
-
private:
/**
@@ -125,16 +148,45 @@
*/
std::string FindCreator (void);
+ /**
+ * Spin up the device
+ */
+ void StartTapDevice (void);
+
+ /**
+ * Tear down the device
+ */
+ void StopTapDevice (void);
+
+ /**
+ * Loop to read and process packets
+ */
+ void ReadThread (void);
+
+ void ForwardToBridgedDevice (uint8_t *buf, uint32_t len);
+
NetDevice::ReceiveCallback m_rxCallback;
NetDevice::PromiscReceiveCallback m_promiscRxCallback;
- Mac48Address m_address;
Ptr<Node> m_node;
std::string m_name;
uint32_t m_ifIndex;
uint16_t m_mtu;
+ int32_t m_sock;
+ EventId m_startEvent;
+ EventId m_stopEvent;
+ Ptr<SystemThread> m_readThread;
+ Mac48Address m_address;
- int32_t m_sock;
+ /**
+ * Time to start spinning up the device
+ */
+ Time m_tStart;
+
+ /**
+ * Time to start tearing down the device
+ */
+ Time m_tStop;
std::string m_tapDeviceName;
std::string m_tapGateway;