Get emu working again: Add Dix/Llc option, add and use contextual realtime schedule ops, don't refcount realtime simulator impl
--- a/bindings/python/apidefs/gcc-ILP32/ns3_module_emu.py Mon Nov 30 14:46:02 2009 -0800
+++ b/bindings/python/apidefs/gcc-ILP32/ns3_module_emu.py Mon Nov 30 18:22:10 2009 -0800
@@ -5,6 +5,8 @@
## emu-net-device.h: ns3::EmuNetDevice [class]
module.add_class('EmuNetDevice', parent=root_module['ns3::NetDevice'])
+ ## emu-net-device.h: ns3::EmuNetDevice::EncapsulationMode [enumeration]
+ module.add_enum('EncapsulationMode', ['ILLEGAL', 'DIX', 'LLC'], outer_class=root_module['ns3::EmuNetDevice'])
## Register a nested module for the namespace Config
@@ -115,6 +117,11 @@
'ns3::Ptr< ns3::Channel >',
[],
is_const=True, is_virtual=True)
+ ## emu-net-device.h: ns3::EmuNetDevice::EncapsulationMode ns3::EmuNetDevice::GetEncapsulationMode() const [member function]
+ cls.add_method('GetEncapsulationMode',
+ 'ns3::EmuNetDevice::EncapsulationMode',
+ [],
+ is_const=True)
## emu-net-device.h: uint32_t ns3::EmuNetDevice::GetIfIndex() const [member function]
cls.add_method('GetIfIndex',
'uint32_t',
@@ -194,6 +201,10 @@
cls.add_method('SetDataRate',
'void',
[param('ns3::DataRate', 'bps')])
+ ## emu-net-device.h: void ns3::EmuNetDevice::SetEncapsulationMode(ns3::EmuNetDevice::EncapsulationMode mode) [member function]
+ cls.add_method('SetEncapsulationMode',
+ 'void',
+ [param('ns3::EmuNetDevice::EncapsulationMode', 'mode')])
## emu-net-device.h: void ns3::EmuNetDevice::SetIfIndex(uint32_t const index) [member function]
cls.add_method('SetIfIndex',
'void',
--- a/bindings/python/apidefs/gcc-ILP32/ns3_module_simulator.py Mon Nov 30 14:46:02 2009 -0800
+++ b/bindings/python/apidefs/gcc-ILP32/ns3_module_simulator.py Mon Nov 30 18:22:10 2009 -0800
@@ -1486,6 +1486,14 @@
cls.add_method('ScheduleRealtimeNow',
'void',
[param('ns3::EventImpl *', 'event')])
+ ## realtime-simulator-impl.h: void ns3::RealtimeSimulatorImpl::ScheduleRealtimeNowWithContext(uint32_t context, ns3::EventImpl * event) [member function]
+ cls.add_method('ScheduleRealtimeNowWithContext',
+ 'void',
+ [param('uint32_t', 'context'), param('ns3::EventImpl *', 'event')])
+ ## realtime-simulator-impl.h: void ns3::RealtimeSimulatorImpl::ScheduleRealtimeWithContext(uint32_t context, ns3::Time const & time, ns3::EventImpl * event) [member function]
+ cls.add_method('ScheduleRealtimeWithContext',
+ 'void',
+ [param('uint32_t', 'context'), param('ns3::Time const &', 'time'), param('ns3::EventImpl *', 'event')])
## realtime-simulator-impl.h: void ns3::RealtimeSimulatorImpl::ScheduleWithContext(uint32_t context, ns3::Time const & time, ns3::EventImpl * event) [member function]
cls.add_method('ScheduleWithContext',
'void',
--- a/bindings/python/apidefs/gcc-LP64/ns3_module_emu.py Mon Nov 30 14:46:02 2009 -0800
+++ b/bindings/python/apidefs/gcc-LP64/ns3_module_emu.py Mon Nov 30 18:22:10 2009 -0800
@@ -5,6 +5,8 @@
## emu-net-device.h: ns3::EmuNetDevice [class]
module.add_class('EmuNetDevice', parent=root_module['ns3::NetDevice'])
+ ## emu-net-device.h: ns3::EmuNetDevice::EncapsulationMode [enumeration]
+ module.add_enum('EncapsulationMode', ['ILLEGAL', 'DIX', 'LLC'], outer_class=root_module['ns3::EmuNetDevice'])
## Register a nested module for the namespace Config
@@ -115,6 +117,11 @@
'ns3::Ptr< ns3::Channel >',
[],
is_const=True, is_virtual=True)
+ ## emu-net-device.h: ns3::EmuNetDevice::EncapsulationMode ns3::EmuNetDevice::GetEncapsulationMode() const [member function]
+ cls.add_method('GetEncapsulationMode',
+ 'ns3::EmuNetDevice::EncapsulationMode',
+ [],
+ is_const=True)
## emu-net-device.h: uint32_t ns3::EmuNetDevice::GetIfIndex() const [member function]
cls.add_method('GetIfIndex',
'uint32_t',
@@ -194,6 +201,10 @@
cls.add_method('SetDataRate',
'void',
[param('ns3::DataRate', 'bps')])
+ ## emu-net-device.h: void ns3::EmuNetDevice::SetEncapsulationMode(ns3::EmuNetDevice::EncapsulationMode mode) [member function]
+ cls.add_method('SetEncapsulationMode',
+ 'void',
+ [param('ns3::EmuNetDevice::EncapsulationMode', 'mode')])
## emu-net-device.h: void ns3::EmuNetDevice::SetIfIndex(uint32_t const index) [member function]
cls.add_method('SetIfIndex',
'void',
--- a/bindings/python/apidefs/gcc-LP64/ns3_module_simulator.py Mon Nov 30 14:46:02 2009 -0800
+++ b/bindings/python/apidefs/gcc-LP64/ns3_module_simulator.py Mon Nov 30 18:22:10 2009 -0800
@@ -1486,6 +1486,14 @@
cls.add_method('ScheduleRealtimeNow',
'void',
[param('ns3::EventImpl *', 'event')])
+ ## realtime-simulator-impl.h: void ns3::RealtimeSimulatorImpl::ScheduleRealtimeNowWithContext(uint32_t context, ns3::EventImpl * event) [member function]
+ cls.add_method('ScheduleRealtimeNowWithContext',
+ 'void',
+ [param('uint32_t', 'context'), param('ns3::EventImpl *', 'event')])
+ ## realtime-simulator-impl.h: void ns3::RealtimeSimulatorImpl::ScheduleRealtimeWithContext(uint32_t context, ns3::Time const & time, ns3::EventImpl * event) [member function]
+ cls.add_method('ScheduleRealtimeWithContext',
+ 'void',
+ [param('uint32_t', 'context'), param('ns3::Time const &', 'time'), param('ns3::EventImpl *', 'event')])
## realtime-simulator-impl.h: void ns3::RealtimeSimulatorImpl::ScheduleWithContext(uint32_t context, ns3::Time const & time, ns3::EventImpl * event) [member function]
cls.add_method('ScheduleWithContext',
'void',
--- a/examples/emulation/emu-udp-echo.cc Mon Nov 30 14:46:02 2009 -0800
+++ b/examples/emulation/emu-udp-echo.cc Mon Nov 30 18:22:10 2009 -0800
@@ -75,6 +75,7 @@
main (int argc, char *argv[])
{
std::string deviceName ("eth1");
+ std::string encapMode ("Dix");
uint32_t nNodes = 4;
//
@@ -83,7 +84,9 @@
//
CommandLine cmd;
cmd.AddValue("deviceName", "device name", deviceName);
+ cmd.AddValue("encapsulationMode", "encapsulation mode of emu device (\"Dix\" [default] or \"Llc\")", encapMode);
cmd.AddValue("nNodes", "number of nodes to create (>= 2)", nNodes);
+
cmd.Parse (argc, argv);
GlobalValue::Bind ("SimulatorImplementationType",
@@ -110,6 +113,8 @@
NS_LOG_INFO ("Create channels.");
EmuHelper emu;
emu.SetAttribute ("DeviceName", StringValue (deviceName));
+ emu.SetAttribute ("EncapsulationMode", StringValue (encapMode));
+
NetDeviceContainer d = emu.Install (n);
//
@@ -133,8 +138,8 @@
// Create a UdpEchoClient application to send UDP datagrams from node zero to node one.
//
uint32_t packetSize = 1024;
- uint32_t maxPacketCount = 1;
- Time interPacketInterval = Seconds (1.);
+ uint32_t maxPacketCount = 20;
+ Time interPacketInterval = Seconds (0.1);
UdpEchoClientHelper client (i.GetAddress (1), 9);
client.SetAttribute ("MaxPackets", UintegerValue (maxPacketCount));
client.SetAttribute ("Interval", TimeValue (interPacketInterval));
--- a/src/devices/emu/emu-net-device.cc Mon Nov 30 14:46:02 2009 -0800
+++ b/src/devices/emu/emu-net-device.cc Mon Nov 30 18:22:10 2009 -0800
@@ -32,8 +32,8 @@
#include "ns3/trace-source-accessor.h"
#include "ns3/channel.h"
#include "ns3/system-thread.h"
-#include "ns3/realtime-simulator-impl.h"
#include "ns3/mac48-address.h"
+#include "ns3/enum.h"
#include <sys/wait.h>
#include <sys/stat.h>
@@ -83,6 +83,12 @@
TimeValue (Seconds (0.)),
MakeTimeAccessor (&EmuNetDevice::m_tStop),
MakeTimeChecker ())
+ .AddAttribute ("EncapsulationMode",
+ "The link-layer encapsulation type to use.",
+ EnumValue (LLC),
+ MakeEnumAccessor (&EmuNetDevice::SetEncapsulationMode),
+ MakeEnumChecker (DIX, "Dix",
+ LLC, "Llc"))
//
// Transmit queueing discipline for the device which includes its own set
@@ -165,7 +171,6 @@
return tid;
}
-
EmuNetDevice::EmuNetDevice ()
:
m_startEvent (),
@@ -178,11 +183,17 @@
m_isMulticast (false)
{
NS_LOG_FUNCTION (this);
+ m_packetBuffer = new uint8_t[65536];
Start (m_tStart);
}
EmuNetDevice::~EmuNetDevice ()
{
+ if (m_packetBuffer)
+ {
+ delete [] m_packetBuffer;
+ m_packetBuffer = 0;
+ }
}
void
@@ -193,6 +204,21 @@
NetDevice::DoDispose ();
}
+void
+EmuNetDevice::SetEncapsulationMode (enum EncapsulationMode mode)
+{
+ NS_LOG_FUNCTION (mode);
+ m_encapMode = mode;
+ NS_LOG_LOGIC ("m_encapMode = " << m_encapMode);
+}
+
+EmuNetDevice::EncapsulationMode
+EmuNetDevice::GetEncapsulationMode (void) const
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ return m_encapMode;
+}
+
void
EmuNetDevice::Start (Time tStart)
{
@@ -203,6 +229,20 @@
//
Simulator::Cancel (m_startEvent);
m_startEvent = Simulator::Schedule (tStart, &EmuNetDevice::StartDevice, this);
+
+ //
+ // We're going to need a pointer to the realtime simulator implementation.
+ // It's important to remember that access to that implementation may happen
+ // in a completely different thread than the simulator is running in. We are
+ // talking about multiple threads here, so it is very, very dangerous to do
+ // any kind of reference couning on a shared object. So what we are going to
+ // do is to get a reference to the realtime simulator and then save a raw
+ // pointer to that implementation for use by the other threads. We must not
+ // free this pointer or we may delete the simulator out from under us an
+ // everyone else.
+ //
+ Ptr<RealtimeSimulatorImpl> impl = DynamicCast<RealtimeSimulatorImpl> (Simulator::GetImplementation ());
+ m_rtImpl = GetPointer (impl);
}
void
@@ -308,6 +348,7 @@
// This one is OK to enable at runtime
m_isMulticast = true;
}
+
//
// Now spin up a read thread to read packets.
//
@@ -563,6 +604,10 @@
locations.push_back ("../../../build/optimized/src/devices/emu/");
locations.push_back ("../../../build/debug/src/devices/emu/");
+ // src/devices/emu (or build/debug/examples/emulation)
+ locations.push_back ("../../../../build/optimized/src/devices/emu/");
+ locations.push_back ("../../../../build/debug/src/devices/emu/");
+
for (std::list<std::string>::const_iterator i = locations.begin (); i != locations.end (); ++i)
{
struct stat st;
@@ -632,31 +677,43 @@
uint16_t protocol;
- //
- // 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)
+ switch (m_encapMode)
{
- LlcSnapHeader llc;
+ case LLC:
//
- // Check to see that the packet is long enough to possibly contain the
- // header we want to remove before just naively calling.
+ // 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 (packet->GetSize() < llc.GetSerializedSize())
+ if (header.GetLengthType () <= 1500)
{
- m_phyRxDropTrace (originalPacket);
- return;
- }
+ LlcSnapHeader llc;
+ //
+ // Check to see that the packet is long enough to possibly contain the
+ // header we want to remove before just naively calling.
+ //
+ if (packet->GetSize() < llc.GetSerializedSize())
+ {
+ m_phyRxDropTrace (originalPacket);
+ return;
+ }
- packet->RemoveHeader (llc);
- protocol = llc.GetType ();
- }
- else
- {
+ packet->RemoveHeader (llc);
+ protocol = llc.GetType ();
+ }
+ else
+ {
+ protocol = header.GetLengthType ();
+ }
+ break;
+
+ case DIX:
protocol = header.GetLengthType ();
+ break;
+
+ default:
+ NS_FATAL_ERROR ("invalid encapsulation mode");
}
PacketType packetType;
@@ -709,13 +766,9 @@
{
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 forward up 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.
+ // It's important to remember that we're in a completely different thread than the simulator is running in.
+ // We are talking about multiple threads here, so it is very, very dangerous to do any kind of reference couning
+ // on a shared object.
//
int32_t len = -1;
@@ -724,6 +777,10 @@
for (;;)
{
+ //
+ // to avoid any issues with a shared reference counted packet, we allocate a buffer on the heap and pass that
+ // buffer into the ns-3 context thread where it will create the packet, copy the buffer and then free it.
+ //
uint32_t bufferSize = 65536;
uint8_t *buf = (uint8_t *)malloc (bufferSize);
if (buf == 0)
@@ -743,8 +800,8 @@
NS_LOG_INFO ("EmuNetDevice::ReadThread(): Received packet");
NS_LOG_INFO ("EmuNetDevice::ReadThread(): Scheduling handler");
- DynamicCast<RealtimeSimulatorImpl> (Simulator::GetImplementation ())->ScheduleRealtimeNow (
- MakeEvent (&EmuNetDevice::ForwardUp, this, buf, len));
+ NS_ASSERT_MSG (m_rtImpl, "EmuNetDevice::ReadThread(): Realtime simulator implementation pointer not set");
+ m_rtImpl->ScheduleRealtimeNowWithContext (GetNode ()->GetId (), MakeEvent (&EmuNetDevice::ForwardUp, this, buf, len));
buf = 0;
}
}
@@ -795,19 +852,30 @@
NS_LOG_LOGIC ("Transmit packet from " << source);
NS_LOG_LOGIC ("Transmit packet to " << destination);
- //
- // We've got to pick either DIX (Ethernet) or LLC/SNAP (IEEE 802.3) as a
- // packet format. IEEE 802.3 is slightly more formally correct, so we
- // go that route.
- //
- LlcSnapHeader llc;
- llc.SetType (protocolNumber);
- packet->AddHeader (llc);
-
EthernetHeader header (false);
header.SetSource (source);
header.SetDestination (destination);
- header.SetLengthType (packet->GetSize ());
+
+ switch (m_encapMode)
+ {
+ case LLC:
+ {
+ LlcSnapHeader llc;
+ llc.SetType (protocolNumber);
+ packet->AddHeader (llc);
+
+ header.SetLengthType (packet->GetSize ());
+ }
+ break;
+
+ case DIX:
+ header.SetLengthType (protocolNumber);
+ break;
+
+ default:
+ NS_FATAL_ERROR ("invalid encapsulation mode");
+ }
+
packet->AddHeader (header);
//
@@ -827,7 +895,6 @@
m_promiscSnifferTrace (packet);
m_snifferTrace (packet);
-
struct sockaddr_ll ll;
bzero (&ll, sizeof (ll));
@@ -837,8 +904,10 @@
NS_LOG_LOGIC ("calling sendto");
- int32_t rc;
- rc = sendto (m_sock, packet->PeekData (), packet->GetSize (), 0, reinterpret_cast<struct sockaddr *> (&ll), sizeof (ll));
+ NS_ASSERT_MSG (packet->GetSize () <= 65536, "EmuNetDevice::SendFrom(): Packet too big " << packet->GetSize ());
+ packet->CopyData (m_packetBuffer, packet->GetSize ());
+
+ int32_t rc = sendto (m_sock, m_packetBuffer, packet->GetSize (), 0, reinterpret_cast<struct sockaddr *> (&ll), sizeof (ll));
NS_LOG_LOGIC ("sendto returns " << rc);
return rc == -1 ? false : true;
--- a/src/devices/emu/emu-net-device.h Mon Nov 30 14:46:02 2009 -0800
+++ b/src/devices/emu/emu-net-device.h Mon Nov 30 18:22:10 2009 -0800
@@ -32,6 +32,7 @@
#include "ns3/ptr.h"
#include "ns3/mac48-address.h"
#include "ns3/system-thread.h"
+#include "ns3/realtime-simulator-impl.h"
namespace ns3 {
@@ -47,6 +48,15 @@
static TypeId GetTypeId (void);
/**
+ * Enumeration of the types of packets supported in the class.
+ */
+ enum EncapsulationMode {
+ ILLEGAL, /**< Encapsulation mode not set */
+ DIX, /**< DIX II / Ethernet II packet */
+ LLC, /**< 802.2 LLC/SNAP Packet*/
+ };
+
+ /**
* Construct a EmuNetDevice
*
* This is the constructor for the EmuNetDevice. It takes as a
@@ -176,6 +186,22 @@
virtual bool SupportsSendFrom (void) const;
+ /**
+ * Set the encapsulation mode of this device.
+ *
+ * \param mode The encapsulation mode of this device.
+ *
+ * \see SetFrameSize
+ */
+ void SetEncapsulationMode (EmuNetDevice::EncapsulationMode mode);
+
+ /**
+ * Get the encapsulation mode of this device.
+ *
+ * \returns The encapsulation mode of this device.
+ */
+ EmuNetDevice::EncapsulationMode GetEncapsulationMode (void) const;
+
private:
virtual void DoDispose (void);
@@ -445,6 +471,13 @@
int32_t m_sll_ifindex;
/**
+ * The type of packet that should be created by the AddHeader
+ * function and that should be processed by the ProcessHeader
+ * function.
+ */
+ EncapsulationMode m_encapMode;
+
+ /**
* Flag indicating whether or not the link is up. In this case,
* whether or not the device is connected to a channel.
*/
@@ -471,6 +504,17 @@
* The unix/linux name of the underlying device (e.g., eth0)
*/
std::string m_deviceName;
+
+ /**
+ * A 64K buffer to hold packet data while it is being sent.
+ */
+ uint8_t *m_packetBuffer;
+
+ /**
+ * A copy of a raw pointer to the required real-time simulator implementation.
+ * Never free this pointer!
+ */
+ RealtimeSimulatorImpl *m_rtImpl;
};
} // namespace ns3
--- a/src/simulator/realtime-simulator-impl.cc Mon Nov 30 14:46:02 2009 -0800
+++ b/src/simulator/realtime-simulator-impl.cc Mon Nov 30 18:22:10 2009 -0800
@@ -620,10 +620,9 @@
// Schedule an event for a _relative_ time in the future.
//
void
-RealtimeSimulatorImpl::ScheduleRealtime (Time const &time, EventImpl *impl)
+RealtimeSimulatorImpl::ScheduleRealtimeWithContext (uint32_t context, Time const &time, EventImpl *impl)
{
- NS_LOG_FUNCTION (time << impl);
-
+ NS_LOG_FUNCTION (context << time << impl);
{
CriticalSection cs (m_mutex);
@@ -639,13 +638,19 @@
m_events->Insert (ev);
m_synchronizer->Signal ();
}
-
}
void
-RealtimeSimulatorImpl::ScheduleRealtimeNow (EventImpl *impl)
+RealtimeSimulatorImpl::ScheduleRealtime (Time const &time, EventImpl *impl)
{
- NS_LOG_FUNCTION_NOARGS ();
+ NS_LOG_FUNCTION (time << impl);
+ ScheduleRealtimeWithContext (GetContext (), time, impl);
+}
+
+void
+RealtimeSimulatorImpl::ScheduleRealtimeNowWithContext (uint32_t context, EventImpl *impl)
+{
+ NS_LOG_FUNCTION (context << impl);
{
CriticalSection cs (m_mutex);
@@ -654,11 +659,13 @@
// realtime clock. If we're not, then m_currentTs is were we stopped.
//
uint64_t ts = m_running ? m_synchronizer->GetCurrentRealtime () : m_currentTs;
- NS_ASSERT_MSG (ts >= m_currentTs, "RealtimeSimulatorImpl::ScheduleRealtimeNow(): schedule for time < m_currentTs");
+ NS_ASSERT_MSG (ts >= m_currentTs,
+ "RealtimeSimulatorImpl::ScheduleRealtimeNowWithContext(): schedule for time < m_currentTs");
Scheduler::Event ev;
ev.impl = impl;
ev.key.m_ts = ts;
ev.key.m_uid = m_uid;
+ ev.key.m_context = context;
m_uid++;
m_unscheduledEvents++;
m_events->Insert (ev);
@@ -666,6 +673,13 @@
}
}
+void
+RealtimeSimulatorImpl::ScheduleRealtimeNow (EventImpl *impl)
+{
+ NS_LOG_FUNCTION (impl);
+ ScheduleRealtimeNowWithContext (GetContext (), impl);
+}
+
Time
RealtimeSimulatorImpl::RealtimeNow (void) const
{
--- a/src/simulator/realtime-simulator-impl.h Mon Nov 30 14:46:02 2009 -0800
+++ b/src/simulator/realtime-simulator-impl.h Mon Nov 30 18:22:10 2009 -0800
@@ -71,7 +71,9 @@
virtual void SetScheduler (ObjectFactory schedulerFactory);
virtual uint32_t GetContext (void) const;
+ void ScheduleRealtimeWithContext (uint32_t context, Time const &time, EventImpl *event);
void ScheduleRealtime (Time const &time, EventImpl *event);
+ void ScheduleRealtimeNowWithContext (uint32_t context, EventImpl *event);
void ScheduleRealtimeNow (EventImpl *event);
Time RealtimeNow (void) const;