Get emu working again: Add Dix/Llc option, add and use contextual realtime schedule ops, don't refcount realtime simulator impl

This commit is contained in:
Craig Dowell
2009-11-30 18:22:10 -08:00
parent 0db2a7250a
commit a0d11b0209
9 changed files with 224 additions and 52 deletions

View File

@@ -5,6 +5,8 @@ def register_types(module):
## 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 @@ def register_Ns3EmuNetDevice_methods(root_module, cls):
'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 @@ def register_Ns3EmuNetDevice_methods(root_module, cls):
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',

View File

@@ -1486,6 +1486,14 @@ def register_Ns3RealtimeSimulatorImpl_methods(root_module, cls):
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',

View File

@@ -5,6 +5,8 @@ def register_types(module):
## 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 @@ def register_Ns3EmuNetDevice_methods(root_module, cls):
'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 @@ def register_Ns3EmuNetDevice_methods(root_module, cls):
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',

View File

@@ -1486,6 +1486,14 @@ def register_Ns3RealtimeSimulatorImpl_methods(root_module, cls):
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',

View File

@@ -75,6 +75,7 @@ int
main (int argc, char *argv[])
{
std::string deviceName ("eth1");
std::string encapMode ("Dix");
uint32_t nNodes = 4;
//
@@ -83,7 +84,9 @@ main (int argc, char *argv[])
//
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 @@ main (int argc, char *argv[])
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 @@ main (int argc, char *argv[])
// 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));

View File

@@ -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 @@ EmuNetDevice::GetTypeId (void)
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 @@ EmuNetDevice::GetTypeId (void)
return tid;
}
EmuNetDevice::EmuNetDevice ()
:
m_startEvent (),
@@ -178,11 +183,17 @@ EmuNetDevice::EmuNetDevice ()
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 @@ EmuNetDevice::DoDispose()
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 @@ EmuNetDevice::Start (Time tStart)
//
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 @@ EmuNetDevice::StartDevice (void)
// This one is OK to enable at runtime
m_isMulticast = true;
}
//
// Now spin up a read thread to read packets.
//
@@ -563,6 +604,10 @@ EmuNetDevice::FindCreator (std::string creatorName)
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 @@ EmuNetDevice::ForwardUp (uint8_t *buf, uint32_t len)
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 @@ EmuNetDevice::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 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 @@ EmuNetDevice::ReadThread (void)
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 @@ EmuNetDevice::ReadThread (void)
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 @@ EmuNetDevice::SendFrom (Ptr<Packet> packet, const Address &src, const Address &d
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 @@ EmuNetDevice::SendFrom (Ptr<Packet> packet, const Address &src, const Address &d
m_promiscSnifferTrace (packet);
m_snifferTrace (packet);
struct sockaddr_ll ll;
bzero (&ll, sizeof (ll));
@@ -837,8 +904,10 @@ EmuNetDevice::SendFrom (Ptr<Packet> packet, const Address &src, const Address &d
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;

View File

@@ -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 {
@@ -46,6 +47,15 @@ class EmuNetDevice : public NetDevice
public:
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
*
@@ -176,6 +186,22 @@ public:
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);
@@ -444,6 +470,13 @@ private:
*/
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 @@ private:
* 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

View File

@@ -620,10 +620,9 @@ RealtimeSimulatorImpl::Now (void) const
// 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 @@ RealtimeSimulatorImpl::ScheduleRealtime (Time const &time, EventImpl *impl)
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 @@ RealtimeSimulatorImpl::ScheduleRealtimeNow (EventImpl *impl)
// 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 @@ RealtimeSimulatorImpl::ScheduleRealtimeNow (EventImpl *impl)
}
}
void
RealtimeSimulatorImpl::ScheduleRealtimeNow (EventImpl *impl)
{
NS_LOG_FUNCTION (impl);
ScheduleRealtimeNowWithContext (GetContext (), impl);
}
Time
RealtimeSimulatorImpl::RealtimeNow (void) const
{

View File

@@ -71,7 +71,9 @@ public:
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;