# HG changeset patch # User Florian Westphal # Date 1247676374 -7200 # Node ID ae536d9e0d6d0a8ef6515224c3a1c44aae0ced84 # Parent 44b325571ab4d6d56b1c44a7bedc925c2af1b5b8 nsc: move nsc glue code from nsc-tcp-l4-protocol to node/nsc-glue.cc. known problems: - sim_interface.h is duplicated - nsc-glue.cc adds hooks in node.cc, "hijacks" incoming packets - nsc-glue exports NSCs INetStack (instead of wrapping it completely) - nsc-tcp-l4-protocol and nsc-tcp-socket-impl make calls into nsc-glue - nsc-tcp-socket-impl should really be "nsc-socket-core" (or something like that) needs fixing on nsc side: - no support for multiple interfaces yet (also not yet supported on nsc side) - nsc initialisation still tied to IP (Adding an Interface and assigning the IP address is a single step; it should be separate) maybe there is more. There is a NSC_NEXT define in nsc-glue.h, its main purpose is to flag the places where the NSC API needs to be adapted to support multiple interfaces in nsc. diff -r 44b325571ab4 -r ae536d9e0d6d src/internet-stack/nsc-sysctl.cc --- a/src/internet-stack/nsc-sysctl.cc Wed Jul 15 14:59:44 2009 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,154 +0,0 @@ -/* -*- 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 - * - * Author: Mathieu Lacage - */ - -#include "ns3/string.h" -#include "nsc-sysctl.h" - -#include "sim_interface.h" - -namespace ns3 { - -class NscStackStringAccessor : public AttributeAccessor -{ - public: - NscStackStringAccessor (std::string name) : m_name (name) {} - - virtual bool Set (ObjectBase * object, const AttributeValue &val) const; - virtual bool Get (const ObjectBase * object, AttributeValue &val) const; - virtual bool HasGetter (void) const; - virtual bool HasSetter (void) const; - private: - std::string m_name; -}; - -bool NscStackStringAccessor::HasGetter(void) const -{ - return true; -} - -bool NscStackStringAccessor::HasSetter(void) const -{ - return true; -} - - -bool NscStackStringAccessor::Set (ObjectBase * object, const AttributeValue & val) const -{ - const StringValue *value = dynamic_cast (&val); - if (value == 0) - { - return false; - } - Ns3NscStack *obj = dynamic_cast (object); - if (obj == 0) - { - return false; - } - obj->Set (m_name, value->Get ()); - return true; -} - -bool NscStackStringAccessor::Get (const ObjectBase * object, AttributeValue &val) const -{ - StringValue *value = dynamic_cast (&val); - if (value == 0) - { - return false; - } - const Ns3NscStack *obj = dynamic_cast (object); - if (obj == 0) - { - return false; - } - value->Set (obj->Get (m_name)); - return true; -} - - -TypeId -Ns3NscStack::GetInstanceTypeId (void) const -{ - if (m_stack == 0) - { - // if we have no stack, we are a normal NscStack without any attributes. - return GetTypeId (); - } - std::string name = "ns3::Ns3NscStack<"; - name += m_stack->get_name (); - name += ">"; - TypeId tid; - if (TypeId::LookupByNameFailSafe (name, &tid)) - { - // if the relevant TypeId has already been registered, no need to do it again. - return tid; - } - else - { - // Now, we register a new TypeId for this stack which will look - // like a subclass of the Ns3NscStack. The class Ns3NscStack is effectively - // mutating into a subclass of itself from the point of view of the TypeId - // system _here_ - tid = TypeId (name.c_str ()); - tid.SetParent (); - char buf[256]; - for (int i=0; m_stack->sysctl_getnum(i, buf, sizeof(buf)) > 0 ;i++) - { - char value[256]; - if (m_stack->sysctl_get (buf, value, sizeof(value)) > 0) - { - tid.AddAttribute (buf, "Help text", - StringValue (value), - Create (buf), - MakeStringChecker ()); - } - } - return tid; - } -} - -std::string -Ns3NscStack::Get (std::string name) const -{ - char buf[512]; - if (m_stack->sysctl_get (name.c_str (), buf, sizeof(buf)) <= 0) - { // name.c_str () is not a valid sysctl name, or internal NSC error (eg. error converting value) - return NULL; - } - return std::string(buf); -} - -void -Ns3NscStack::Set (std::string name, std::string value) -{ - int ret = m_stack->sysctl_set (name.c_str (), value.c_str ()); - if (ret < 0) - { - NS_FATAL_ERROR ("setting " << name << " to " << value << "failed (retval " << ret << ")"); - } -} - -TypeId -Ns3NscStack::Ns3NscStack::GetTypeId (void) -{ - static TypeId tid = TypeId ("ns3::Ns3NscStack") - .SetParent () - ; - return tid; -} - -} // namespace ns3 diff -r 44b325571ab4 -r ae536d9e0d6d src/internet-stack/nsc-sysctl.h --- a/src/internet-stack/nsc-sysctl.h Wed Jul 15 14:59:44 2009 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,44 +0,0 @@ -/* -*- 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 - * - * Author: Mathieu Lacage - */ - -#include - -#include "ns3/attribute.h" -#include "ns3/object.h" - -struct INetStack; - -namespace ns3 { - -// This object represents the underlying nsc stack, -// which is aggregated to a Node object, and which provides access to the -// sysctls of the nsc stack through attributes. -class Ns3NscStack : public Object -{ -public: - static TypeId GetTypeId (void); - virtual TypeId GetInstanceTypeId (void) const; - void SetStack (INetStack *stack) {m_stack = stack;} - -private: - friend class NscStackStringAccessor; - void Set (std::string name, std::string value); - std::string Get (std::string name) const; - INetStack *m_stack; -}; -} // namespace ns3 diff -r 44b325571ab4 -r ae536d9e0d6d src/internet-stack/nsc-tcp-l4-protocol.cc --- a/src/internet-stack/nsc-tcp-l4-protocol.cc Wed Jul 15 14:59:44 2009 +0200 +++ b/src/internet-stack/nsc-tcp-l4-protocol.cc Wed Jul 15 18:46:14 2009 +0200 @@ -19,7 +19,6 @@ #include "ns3/assert.h" #include "ns3/log.h" -#include "ns3/nstime.h" #include "ns3/packet.h" #include "ns3/node.h" @@ -32,7 +31,7 @@ #include "ipv4-end-point.h" #include "ipv4-l3-protocol.h" #include "nsc-tcp-l4-protocol.h" -#include "nsc-sysctl.h" + #include "nsc-tcp-socket-factory-impl.h" #include "tcp-typedefs.h" @@ -87,36 +86,18 @@ return tid; } -int external_rand() +NscTcpL4Protocol::NscTcpL4Protocol () + : m_endPoints (new Ipv4EndPointDemux ()) { - return 1; // TODO -} - -NscTcpL4Protocol::NscTcpL4Protocol () - : m_endPoints (new Ipv4EndPointDemux ()), - m_nscStack (0), - m_softTimer (Timer::CANCEL_ON_DESTROY) -{ - m_dlopenHandle = NULL; NS_LOG_LOGIC("Made a NscTcpL4Protocol "< node) { m_node = node; - - if (m_nscStack) - { // stack has already been loaded... - return; - } - - NS_ASSERT(m_dlopenHandle); - - FCreateStack create = (FCreateStack)dlsym(m_dlopenHandle, "nsc_create_stack"); - NS_ASSERT(create); - m_nscStack = create(this, this, external_rand); - int hzval = m_nscStack->get_hz(); - - NS_ASSERT(hzval > 0); - - m_softTimer.SetFunction (&NscTcpL4Protocol::SoftInterrupt, this); - m_softTimer.SetDelay (MilliSeconds (1000/hzval)); - m_nscStack->init(hzval); - // This enables stack and NSC debug messages - // m_nscStack->set_diagnostic(1000); - - Ptr nscStack = Create (); - nscStack->SetStack (m_nscStack); - node->AggregateObject (nscStack); - - m_softTimer.Schedule (); - - // its likely no ns-3 interface exits at this point, so - // we dealy adding the nsc interface until the start of the simulation. - Simulator::ScheduleNow (&NscTcpL4Protocol::AddInterface, this); + m_node->SetNscLibrary (m_nscLibrary); + m_node->RegisterNscWakeupCallback (MakeCallback (&NscTcpL4Protocol::Wakeup , this)); } void @@ -270,82 +225,10 @@ NscTcpL4Protocol::DeAllocate (Ipv4EndPoint *endPoint) { NS_LOG_FUNCTION (this << endPoint); - // NSC m_endPoints->DeAllocate (endPoint); + m_endPoints->DeAllocate (endPoint); } -Ipv4L4Protocol::RxStatus -NscTcpL4Protocol::Receive (Ptr packet, - Ipv4Address const &source, - Ipv4Address const &destination, - Ptr incomingInterface) -{ - NS_LOG_FUNCTION (this << packet << source << destination << incomingInterface); - Ipv4Header ipHeader; - uint32_t packetSize = packet->GetSize(); - - // The way things work at the moment, the IP header has been removed - // by the ns-3 IPv4 processing code. However, the NSC stack expects - // a complete IP packet, so we add the IP header back. - // Since the original header is already gone, we create a new one - // based on the information we have. - ipHeader.SetSource (source); - ipHeader.SetDestination (destination); - ipHeader.SetProtocol (PROT_NUMBER); - ipHeader.SetPayloadSize (packetSize); - ipHeader.SetTtl (1); - // all NSC stacks check the IP checksum - ipHeader.EnableChecksum (); - - packet->AddHeader(ipHeader); - packetSize = packet->GetSize(); - - const uint8_t *data = const_cast(packet->PeekData()); - - // deliver complete packet to the NSC network stack - m_nscStack->if_receive_packet(0, data, packetSize); - wakeup (); - return Ipv4L4Protocol::RX_OK; -} - -void NscTcpL4Protocol::SoftInterrupt (void) -{ - m_nscStack->timer_interrupt (); - m_nscStack->increment_ticks (); - m_softTimer.Schedule (); -} - -void NscTcpL4Protocol::send_callback(const void* data, int datalen) -{ - Ptr p; - uint32_t ipv4Saddr, ipv4Daddr; - - NS_ASSERT(datalen > 20); - - - // create packet, without IP header. The TCP header is not touched. - // Not using the IP header makes integration easier, but it destroys - // eg. ECN. - const uint8_t *rawdata = reinterpret_cast(data); - rawdata += 20; // skip IP header. IP options aren't supported at this time. - datalen -= 20; - p = Create (rawdata, datalen); - - // we need the real source/destination ipv4 addresses for Send (). - const uint32_t *ipheader = reinterpret_cast(data); - ipv4Saddr = *(ipheader+3); - ipv4Daddr = *(ipheader+4); - - Ipv4Address saddr(ntohl(ipv4Saddr)); - Ipv4Address daddr(ntohl(ipv4Daddr)); - - Ptr ipv4 = m_node->GetObject (); - NS_ASSERT_MSG (ipv4, "nsc callback invoked, but node has no ipv4 object"); - - ipv4->Send (p, saddr, daddr, PROT_NUMBER, 0); - m_nscStack->if_send_finish(0); -} - -void NscTcpL4Protocol::wakeup() +void NscTcpL4Protocol::Wakeup() { // TODO // this should schedule a timer to read from all tcp sockets now... this is @@ -359,70 +242,13 @@ } } -void NscTcpL4Protocol::gettime(unsigned int* sec, unsigned int* usec) -{ - // Only used by the Linux network stack, e.g. during ISN generation - // and in the kernel rng initialization routine. Also used in Linux - // printk output. - Time t = Simulator::Now (); - int64_t us = t.GetMicroSeconds (); - *sec = us / (1000*1000); - *usec = us - *sec * (1000*1000); -} - - -void NscTcpL4Protocol::AddInterface(void) -{ - Ptr ip = m_node->GetObject (); - const uint32_t nInterfaces = ip->GetNInterfaces (); - - NS_ASSERT_MSG (nInterfaces <= 2, "nsc does not support multiple interfaces per node"); - - // start from 1, ignore the loopback interface (HACK) - // we really don't need the loop, but its here to illustrate - // how things _should_ be (once nsc can deal with multiple interfaces...) - for (uint32_t i = 1; i < nInterfaces; i++) - { - Ipv4InterfaceAddress ifAddr = ip->GetAddress (i, 0); - Ipv4Address addr = ifAddr.GetLocal (); - Ipv4Mask mask = ifAddr.GetMask (); - uint16_t mtu = ip->GetMtu (i); - - std::ostringstream addrOss, maskOss; - - addr.Print(addrOss); - mask.Print(maskOss); - - NS_LOG_LOGIC ("if_attach " << addrOss.str().c_str() << " " << maskOss.str().c_str() << " " << mtu); - - std::string addrStr = addrOss.str(); - std::string maskStr = maskOss.str(); - const char* addrCStr = addrStr.c_str(); - const char* maskCStr = maskStr.c_str(); - m_nscStack->if_attach(addrCStr, maskCStr, mtu); - - if (i == 1) - { - // We need to come up with a default gateway here. Can't guarantee this to be - // correct really... - - uint8_t addrBytes[4]; - addr.Serialize(addrBytes); - - // XXX: this is all a bit of a horrible hack - // - // Just increment the last octet, this gives a decent chance of this being - // 'enough'. - // - // All we need is another address on the same network as the interface. This - // will force the stack to output the packet out of the network interface. - addrBytes[3]++; - addr.Deserialize(addrBytes); - addrOss.str(""); - addr.Print(addrOss); - m_nscStack->add_default_gateway(addrOss.str().c_str()); - } - } +Ipv4L4Protocol::RxStatus +NscTcpL4Protocol::Receive (Ptr p, + Ipv4Address const &source, + Ipv4Address const &destination, + Ptr incomingInterface) +{ // STUB, RX happens in node/node.cc if NSC is in use. + return Ipv4L4Protocol::RX_OK; } }; // namespace ns3 diff -r 44b325571ab4 -r ae536d9e0d6d src/internet-stack/nsc-tcp-l4-protocol.h --- a/src/internet-stack/nsc-tcp-l4-protocol.h Wed Jul 15 14:59:44 2009 +0200 +++ b/src/internet-stack/nsc-tcp-l4-protocol.h Wed Jul 15 18:46:14 2009 +0200 @@ -29,10 +29,8 @@ #include "tcp-header.h" -#include "ns3/timer.h" +#include "nsc-tcp-socket-impl.h" #include "sim_interface.h" -#include "nsc-tcp-socket-impl.h" - namespace ns3 { class Node; @@ -40,10 +38,10 @@ class TcpHeader; /** * \ingroup nsctcp - * + * * \brief Nsc wrapper glue, to interface with the Ipv4 protocol underneath. */ -class NscTcpL4Protocol : public Ipv4L4Protocol, ISendCallback, IInterruptCallback { +class NscTcpL4Protocol : public Ipv4L4Protocol { public: static const uint8_t PROT_NUMBER; static TypeId GetTypeId (void); @@ -51,11 +49,13 @@ * \brief Constructor */ NscTcpL4Protocol (); - virtual ~NscTcpL4Protocol (); void SetNode (Ptr node); + + // legacy, moved to node/node.cc void SetNscLibrary (const std::string &lib); std::string GetNscLibrary (void) const; + virtual int GetProtocolNumber (void) const; virtual int GetVersion (void) const; @@ -81,27 +81,12 @@ * \param destination The destinations Ipv4Address * \param incomingInterface The Ipv4Interface it was received on */ + + // Stub function, not used in nsc virtual Ipv4L4Protocol::RxStatus Receive (Ptr p, - Ipv4Address const &source, - Ipv4Address const &destination, - Ptr incomingInterface); - - // NSC callbacks. - // NSC invokes these hooks to interact with the simulator. - // In any case, these methods are only to be called by NSC. - // - // send_callback is invoked by NSCs 'ethernet driver' to re-inject - // a packet (i.e. an octet soup consisting of an IP Header, TCP Header - // and user payload, if any), into ns-3. - virtual void send_callback(const void *data, int datalen); - // This is called by the NSC stack whenever something of interest - // has happened, e.g. when data arrives on a socket, a listen socket - // has a new connection pending, etc. - virtual void wakeup(); - // This is called by the Linux stack RNG initialization. - // Its also used by the cradle code to add a timestamp to - // printk/printf/debug output. - virtual void gettime(unsigned int *, unsigned int *); + Ipv4Address const &source, + Ipv4Address const &destination, + Ptr incomingInterface); protected: virtual void DoDispose (void); @@ -111,14 +96,11 @@ Ipv4EndPointDemux *m_endPoints; ObjectFactory m_rttFactory; private: - void AddInterface (void); - void SoftInterrupt (void); static ObjectFactory GetDefaultRttEstimatorFactory (void); friend class NscTcpSocketImpl; INetStack* m_nscStack; - void *m_dlopenHandle; + void Wakeup (void); std::string m_nscLibrary; - Timer m_softTimer; std::vector > m_sockets; }; diff -r 44b325571ab4 -r ae536d9e0d6d src/internet-stack/nsc-tcp-socket-impl.cc --- a/src/internet-stack/nsc-tcp-socket-impl.cc Wed Jul 15 14:59:44 2009 +0200 +++ b/src/internet-stack/nsc-tcp-socket-impl.cc Wed Jul 15 18:46:14 2009 +0200 @@ -162,10 +162,10 @@ void NscTcpSocketImpl::SetTcp (Ptr tcp) { - m_nscTcpSocket = tcp->m_nscStack->new_tcp_socket(); m_tcp = tcp; + m_nscTcpSocket = m_node->GetNscInetStack()->new_tcp_socket(); } -void +void NscTcpSocketImpl::SetRtt (Ptr rtt) { m_rtt = rtt; diff -r 44b325571ab4 -r ae536d9e0d6d src/internet-stack/nsc-tcp-socket-impl.h --- a/src/internet-stack/nsc-tcp-socket-impl.h Wed Jul 15 14:59:44 2009 +0200 +++ b/src/internet-stack/nsc-tcp-socket-impl.h Wed Jul 15 18:46:14 2009 +0200 @@ -32,6 +32,7 @@ #include "sequence-number.h" #include "rtt-estimator.h" +class INetStreamSocket; namespace ns3 { class Ipv4EndPoint; diff -r 44b325571ab4 -r ae536d9e0d6d src/internet-stack/sim_interface.h --- a/src/internet-stack/sim_interface.h Wed Jul 15 14:59:44 2009 +0200 +++ b/src/internet-stack/sim_interface.h Wed Jul 15 18:46:14 2009 +0200 @@ -28,9 +28,19 @@ virtual void init(int hz) = 0; - virtual void if_receive_packet(int if_id, const void *data, int datalen) = 0; - - virtual void if_send_packet(const void *data, int datalen) = 0; + virtual void if_receive_packet(int if_id, const void *data, unsigned int datalen) = 0; + + /* + * called by NSCs network driver. It invokes ISendCallback->send_callback() to pass + * the packet to the simulator. + */ + virtual void if_send_packet(const void *data, unsigned int datalen) = 0; + //virtual void if_send_packet(int if_id, const void *data, unsigned int datalen) = 0; + + /* + * called by network simulator after packet tx was sucessful. + * on Linux, this wakes up the netdev xmit queue. + */ virtual void if_send_finish(int if_id) = 0; virtual void if_attach(const char *addr, const char *mask, int mtu) = 0; @@ -179,7 +189,8 @@ { virtual ~ISendCallback() {} - virtual void send_callback(const void *data, int datalen) = 0; +// virtual void send_callback(int id, const void *data, unsigned int datalen) = 0; + virtual void send_callback(const void *data, unsigned int datalen) = 0; }; struct IInterruptCallback diff -r 44b325571ab4 -r ae536d9e0d6d src/internet-stack/wscript --- a/src/internet-stack/wscript Wed Jul 15 14:59:44 2009 +0200 +++ b/src/internet-stack/wscript Wed Jul 15 18:46:14 2009 +0200 @@ -68,7 +68,6 @@ os.path.abspath(os.path.join(conf.env['WITH_NSC'], nsc_module))) - def build(bld): obj = bld.create_ns3_module('internet-stack', ['node']) obj.source = [ @@ -108,11 +107,12 @@ 'tcp-header.h', 'sequence-number.h', 'icmpv4.h', + 'ipv4-interface.h', + 'ipv4-l3-protocol.h', ] if bld.env['NSC_ENABLED']: obj.source.append ('nsc-tcp-socket-impl.cc') obj.source.append ('nsc-tcp-l4-protocol.cc') obj.source.append ('nsc-tcp-socket-factory-impl.cc') - obj.source.append ('nsc-sysctl.cc') obj.uselib = 'DL' diff -r 44b325571ab4 -r ae536d9e0d6d src/node/node.cc --- a/src/node/node.cc Wed Jul 15 14:59:44 2009 +0200 +++ b/src/node/node.cc Wed Jul 15 18:46:14 2009 +0200 @@ -31,6 +31,8 @@ #include "ns3/global-value.h" #include "ns3/boolean.h" +#include "nsc-glue.h" + NS_LOG_COMPONENT_DEFINE ("Node"); namespace ns3{ @@ -67,7 +69,8 @@ Node::Node() : m_id(0), - m_sid(0) + m_sid(0), + m_useNsc(false) { Construct (); } @@ -251,6 +254,11 @@ << ") Packet UID " << packet->GetUid ()); bool found = false; + if (m_useNsc && m_nscGlue->IsNscProtocol (protocol)) { + m_nscGlue->PassPacketToNsc (packet, 0); // 0: NSC interface ID. XXX: Map &device <-> nscindex + return true; + } + for (ProtocolHandlerList::iterator i = m_handlers.begin (); i != m_handlers.end (); i++) { @@ -271,4 +279,36 @@ return found; } +#ifdef NETWORK_SIMULATION_CRADLE +void +Node::SetNscLibrary(const std::string &soname) +{ + m_nscGlue = CreateObject (); + m_nscGlue->SetNode (this); + m_nscGlue->SetNscLibrary (soname); + + m_useNsc = true; +} + +std::string +Node::GetNscLibrary(void) const +{ + return m_nscGlue->GetNscLibrary (); +} + + + +INetStack * +Node::GetNscInetStack(void) +{ + NS_ASSERT_MSG(m_useNsc, "GetNscInetStack called, but nsc disabled on this node"); + return m_nscGlue->m_nscStack; +} + +void Node::RegisterNscWakeupCallback(Callback cb) +{ + NS_ASSERT (m_nscGlue); + m_nscGlue->RegisterWakeupCallback (cb); +} +#endif }//namespace ns3 diff -r 44b325571ab4 -r ae536d9e0d6d src/node/node.h --- a/src/node/node.h Wed Jul 15 14:59:44 2009 +0200 +++ b/src/node/node.h Wed Jul 15 18:46:14 2009 +0200 @@ -28,12 +28,14 @@ #include "ns3/ptr.h" #include "ns3/net-device.h" +struct INetStack; + namespace ns3 { class Application; class Packet; class Address; - +class NscGlue; /** * \ingroup node @@ -172,13 +174,16 @@ */ void UnregisterProtocolHandler (ProtocolHandler handler); + void SetNscLibrary (const std::string &soname); + std::string GetNscLibrary (void) const; + INetStack* GetNscInetStack(void); + void RegisterNscWakeupCallback (Callback); /** * \returns true if checksums are enabled, false otherwise. */ static bool ChecksumEnabled (void); - protected: /** * The dispose method. Subclasses must override this method @@ -216,6 +221,8 @@ std::vector > m_applications; ProtocolHandlerList m_handlers; + Ptr m_nscGlue; + bool m_useNsc; }; } //namespace ns3 diff -r 44b325571ab4 -r ae536d9e0d6d src/node/nsc-glue.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/node/nsc-glue.cc Wed Jul 15 18:46:14 2009 +0200 @@ -0,0 +1,236 @@ +#include + +#include "ns3/boolean.h" +#include "ns3/log.h" +#include "ns3/ipv4-l3-protocol.h" + +#include "ns3/ipv4-interface.h" +#include "ns3/object.h" +#include "ns3/packet.h" +#include "ns3/ptr.h" +#include "ns3/nstime.h" + +#include "nsc-glue.h" +#include "node.h" + +#include +#include + +namespace ns3 { + +NS_OBJECT_ENSURE_REGISTERED (NscGlue); + +TypeId +NscGlue::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::NscGlue") + .SetParent () + ; + return tid; +} + +NscGlue::NscGlue(void) + : m_wakeupCallbacks(0), + m_dlopenHandle(0) +{ +} + +void +NscGlue::SetNode(Ptr n) +{ + m_node = n; +} + +void +NscGlue::PassPacketToNsc (Ptr packet, int idx) +{ + uint32_t packetSize = packet->GetSize(); + const uint8_t *data = const_cast(packet->PeekData()); + + // deliver complete packet to the NSC network stack + m_nscStack->if_receive_packet(idx, data, packetSize); + wakeup (); +} + +bool +NscGlue::IsNscProtocol (uint16_t proto) +{ + return proto == 0x0800; // NSC can only handle ipv4 at the moment. +} + +static int external_rand(void) +{ + return 1; // XXX: check which NSC stacks actually use this +} + +void +NscGlue::SetNscLibrary(const std::string &soname) +{ + NS_ASSERT(!m_dlopenHandle); + m_dlopenHandle = dlopen(soname.c_str (), RTLD_NOW); + if (m_dlopenHandle == NULL) + NS_FATAL_ERROR (dlerror()); + + FCreateStack create = (FCreateStack)dlsym(m_dlopenHandle, "nsc_create_stack"); + + m_nscStack = create(this, this, external_rand); + int hzval = m_nscStack->get_hz(); + + NS_ASSERT(hzval > 0); + + m_softTimer.SetFunction (&NscGlue::SoftRtcInterrupt, this); + m_softTimer.SetDelay (MilliSeconds (1000/hzval)); + // This enables stack and NSC debug messages + m_nscStack->set_diagnostic(10); + m_nscStack->init(hzval); + + Ptr nscStack = Create (); + nscStack->SetStack (m_nscStack); + m_node->AggregateObject (nscStack); + + m_softTimer.Schedule (); + // its likely no ns-3 interface exits at this point, so + // we delay adding the nsc interface until the start of the simulation. + Simulator::ScheduleNow(&NscGlue::AddIface, this); + + m_nscLibrary = soname; +} + +std::string +NscGlue::GetNscLibrary () const +{ + return m_nscLibrary; +} + + +void NscGlue::wakeup() +{ + // TODO + // this should schedule a timer to read from all tcp sockets now... this is + // an indication that data might be waiting on the socket + for (std::list >::iterator i = m_wakeupCallbacks.begin (); + i != m_wakeupCallbacks.end (); i++) + { + Callback cb = *i; + cb (); + } +} + +void NscGlue::SoftRtcInterrupt (void) +{ + m_nscStack->timer_interrupt (); + m_nscStack->increment_ticks (); + m_softTimer.Schedule (); +} + +void NscGlue::gettime(unsigned int* sec, unsigned int* usec) +{ + // Only used by the Linux network stack, e.g. during ISN generation + // and in the kernel rng initialization routine. Also used in Linux + // printk output. + Time t = Simulator::Now (); + int64_t us = t.GetMicroSeconds (); + *sec = us / (1000*1000); + *usec = us - *sec * (1000*1000); +} + +#ifdef NSC_NEXT +void NscGlue::send_callback(int idx, const void* data, unsigned int datalen) +#else +void NscGlue::send_callback(/* int idx,*/ const void* data, unsigned int datalen) +#endif +{ +#ifndef NSC_NEXT + int idx = 0; +#endif + Ptr p; + uint32_t ipv4Daddr; + + NS_ASSERT(datalen > 20); + + // FIXME: XXX: This won't really work when NSC is able to use + // L3 protocols other than AF_INET. We really really really + // should be able to do all routing decisions inside nsc and just + // pass packets to whatever network interface without looking at its contents. + const uint8_t *rawdata = reinterpret_cast(data); + + p = Create (rawdata, datalen); + + // we need the destination ipv4 address for Send (). + const uint32_t *ipheader = reinterpret_cast(data); + + ipv4Daddr = *(ipheader+4); + + Ipv4Address daddr(ntohl(ipv4Daddr)); + + Ptr ipv4 = m_node->GetObject (); + NS_ASSERT_MSG (ipv4, "nsc callback invoked, but node has no ipv4 object"); + // FIXME: do _all_ routing via NSC and provide a ns3-nsc mapping that + // tells us which ns-3 interface the nsc interface "idx" is corresponding to. +//NS_LOG_LOGIC ("ns3: xmit via device number " << idx); + Ptr outInterface = ipv4->GetInterface ( idx + 1); + + NS_ASSERT (outInterface); + outInterface->Send (p, daddr); + m_nscStack->if_send_finish(0); +} + + +void NscGlue::RegisterWakeupCallback(Callback cb) +{ + m_wakeupCallbacks.push_back (cb); +} + +void NscGlue::AddIface(void) +{ + Ptr ip = m_node->GetObject (); + + const uint32_t nInterfaces = ip->GetNInterfaces (); + // start from 1, ignore the loopback interface (HACK) + + for (uint32_t i = 1; i < nInterfaces; i++) + { + Ipv4InterfaceAddress ifAddr = ip->GetAddress (i, 0); + Ipv4Address addr = ifAddr.GetLocal (); + Ipv4Mask mask = ifAddr.GetMask (); + + uint16_t mtu = ip->GetMtu (i); + + std::ostringstream addrOss, maskOss; + + addr.Print(addrOss); + mask.Print(maskOss); + +// NS_LOG_LOGIC ("if_attach " << addrOss.str().c_str() << " " << maskOss.str().c_str() << " " << mtu); + + std::string addrStr = addrOss.str(); + std::string maskStr = maskOss.str(); + const char* addrCStr = addrStr.c_str(); + const char* maskCStr = maskStr.c_str(); + NS_ASSERT_MSG (m_nscStack, "m_nscStackError"); + m_nscStack->if_attach(addrCStr, maskCStr, mtu); + + if (i == 1) + { + // We need to come up with a default gateway here. Can't guarantee this to be + // correct really... + + uint8_t addrBytes[4]; + addr.Serialize(addrBytes); + + // XXX: this is all a bit of a horrible hack + // + // Just increment the last octet, this gives a decent chance of this being + // 'enough'. + // + // All we need is another address on the same network as the interface. This + // will force the stack to output the packet out of the network interface. + addrBytes[3]++; + addr.Deserialize(addrBytes); + addrOss.str(""); + addr.Print(addrOss); + m_nscStack->add_default_gateway(addrOss.str().c_str()); + } + } +} +} // namespace ns3 diff -r 44b325571ab4 -r ae536d9e0d6d src/node/nsc-glue.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/node/nsc-glue.h Wed Jul 15 18:46:14 2009 +0200 @@ -0,0 +1,116 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2008 Florian Westphal + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Florian Westphal + */ +#ifndef NODE_NSC_H +#define NODE_NSC_H + +#include +#include + +#include "ns3/callback.h" +#include "ns3/ptr.h" +#include "ns3/object.h" +#include "ns3/net-device.h" +#include "ns3/timer.h" + +#include "nsc-sysctl.h" + +#include "sim_interface.h" + +/* + * silly hack to switch betwwen NSC API revisions faster during development. + * should be removed before erging with upstream ns3-dev. + */ +#if NSC_VERSION == 0x00500 +#undef NSC_NEXT +#else +#define NSC_NEXT 1 +#endif + + +namespace ns3 { + +// IInterruptCallback and ISendCallback are NSC interfaces. +class NscGlue : public Object, IInterruptCallback, ISendCallback +{ +public: + static TypeId GetTypeId (void); + + NscGlue (void); + + void SetNode(Ptr n); + void SetNscLibrary(const std::string &soname); + std::string GetNscLibrary () const; + + // returns true if l3 protocol number can be handled by NSC. + // currently only returns true for IPv4. + bool IsNscProtocol (uint16_t proto); + + // passes packet on to NSC. NSC will see the packet arriving on + // interface ifindex. + void PassPacketToNsc (Ptr packet, int ifindex); + + // used to register the L4 wakeup call: + // maybe it should directly be used to register individual + // sockets? + void RegisterWakeupCallback (Callback cb); + + // HACK, make this private. + // Socket implementations should not use m_nscStack-> methods + // directly. + INetStack* m_nscStack; +private: + // IInterruptCallback methods: wakeup and gettime. + // wakeup is called by the NSC stack whenever something of interest + // has happened, e.g. when data arrives on a socket, a listen socket + // has a new connection pending, etc. + virtual void wakeup(); + + // This is called by the Linux stack RNG initialization. + // Its also used by the cradle code to add a timestamp to + // printk/printf/debug output. + virtual void gettime(unsigned int *, unsigned int *); + + // send_callback is invoked by NSCs 'ethernet driver' to re-inject + // a packet (i.e. an octet soup consisting of an IP Header, TCP Header + // and user payload, if any), into ns-3. +#ifdef NSC_NEXT + void send_callback(int idx, const void* data, unsigned int datalen); +#else + void send_callback(const void* data, unsigned int datalen); +#endif + // internal helper. adds ipv4 addresses. + // XXX: rethink. This really doesn't belong here. + // NSC should also split up interface creation and address assignment. + void AddIface(void); + + std::list > m_wakeupCallbacks; + + void *m_dlopenHandle; + Timer m_softTimer; + // called by m_softTimer + void SoftRtcInterrupt (void); + + std::string m_nscLibrary; + Ptr m_node; // sigh... +}; + +} //namespace ns3 + +#endif /* NODE_NSC_H */ diff -r 44b325571ab4 -r ae536d9e0d6d src/node/nsc-sysctl.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/node/nsc-sysctl.cc Wed Jul 15 18:46:14 2009 +0200 @@ -0,0 +1,154 @@ +/* -*- 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 + * + * Author: Mathieu Lacage + */ + +#include "ns3/string.h" +#include "nsc-sysctl.h" + +#include "sim_interface.h" + +namespace ns3 { + +class NscStackStringAccessor : public AttributeAccessor +{ + public: + NscStackStringAccessor (std::string name) : m_name (name) {} + + virtual bool Set (ObjectBase * object, const AttributeValue &val) const; + virtual bool Get (const ObjectBase * object, AttributeValue &val) const; + virtual bool HasGetter (void) const; + virtual bool HasSetter (void) const; + private: + std::string m_name; +}; + +bool NscStackStringAccessor::HasGetter(void) const +{ + return true; +} + +bool NscStackStringAccessor::HasSetter(void) const +{ + return true; +} + + +bool NscStackStringAccessor::Set (ObjectBase * object, const AttributeValue & val) const +{ + const StringValue *value = dynamic_cast (&val); + if (value == 0) + { + return false; + } + Ns3NscStack *obj = dynamic_cast (object); + if (obj == 0) + { + return false; + } + obj->Set (m_name, value->Get ()); + return true; +} + +bool NscStackStringAccessor::Get (const ObjectBase * object, AttributeValue &val) const +{ + StringValue *value = dynamic_cast (&val); + if (value == 0) + { + return false; + } + const Ns3NscStack *obj = dynamic_cast (object); + if (obj == 0) + { + return false; + } + value->Set (obj->Get (m_name)); + return true; +} + + +TypeId +Ns3NscStack::GetInstanceTypeId (void) const +{ + if (m_stack == 0) + { + // if we have no stack, we are a normal NscStack without any attributes. + return GetTypeId (); + } + std::string name = "ns3::Ns3NscStack<"; + name += m_stack->get_name (); + name += ">"; + TypeId tid; + if (TypeId::LookupByNameFailSafe (name, &tid)) + { + // if the relevant TypeId has already been registered, no need to do it again. + return tid; + } + else + { + // Now, we register a new TypeId for this stack which will look + // like a subclass of the Ns3NscStack. The class Ns3NscStack is effectively + // mutating into a subclass of itself from the point of view of the TypeId + // system _here_ + tid = TypeId (name.c_str ()); + tid.SetParent (); + char buf[256]; + for (int i=0; m_stack->sysctl_getnum(i, buf, sizeof(buf)) > 0 ;i++) + { + char value[256]; + if (m_stack->sysctl_get (buf, value, sizeof(value)) > 0) + { + tid.AddAttribute (buf, "Help text", + StringValue (value), + Create (buf), + MakeStringChecker ()); + } + } + return tid; + } +} + +std::string +Ns3NscStack::Get (std::string name) const +{ + char buf[512]; + if (m_stack->sysctl_get (name.c_str (), buf, sizeof(buf)) <= 0) + { // name.c_str () is not a valid sysctl name, or internal NSC error (eg. error converting value) + return NULL; + } + return std::string(buf); +} + +void +Ns3NscStack::Set (std::string name, std::string value) +{ + int ret = m_stack->sysctl_set (name.c_str (), value.c_str ()); + if (ret < 0) + { + NS_FATAL_ERROR ("setting " << name << " to " << value << "failed (retval " << ret << ")"); + } +} + +TypeId +Ns3NscStack::Ns3NscStack::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::Ns3NscStack") + .SetParent () + ; + return tid; +} + +} // namespace ns3 diff -r 44b325571ab4 -r ae536d9e0d6d src/node/nsc-sysctl.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/node/nsc-sysctl.h Wed Jul 15 18:46:14 2009 +0200 @@ -0,0 +1,44 @@ +/* -*- 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 + * + * Author: Mathieu Lacage + */ + +#include + +#include "ns3/attribute.h" +#include "ns3/object.h" + +struct INetStack; + +namespace ns3 { + +// This object represents the underlying nsc stack, +// which is aggregated to a Node object, and which provides access to the +// sysctls of the nsc stack through attributes. +class Ns3NscStack : public Object +{ +public: + static TypeId GetTypeId (void); + virtual TypeId GetInstanceTypeId (void) const; + void SetStack (INetStack *stack) {m_stack = stack;} + +private: + friend class NscStackStringAccessor; + void Set (std::string name, std::string value); + std::string Get (std::string name) const; + INetStack *m_stack; +}; +} // namespace ns3 diff -r 44b325571ab4 -r ae536d9e0d6d src/node/sim_interface.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/node/sim_interface.h Wed Jul 15 18:46:14 2009 +0200 @@ -0,0 +1,211 @@ +#ifndef __SIM_INTERFACE_H__ +#define __SIM_INTERFACE_H__ +/* + Network Simulation Cradle + Copyright (C) 2003-2005 Sam Jansen + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) + any later version. + + 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 + +*/ + +#define NSC_VERSION 0x000500 + +struct INetStack +{ + virtual ~INetStack() {} + + virtual void init(int hz) = 0; + + virtual void if_receive_packet(int if_id, const void *data, unsigned int datalen) = 0; + + /* + * called by NSCs network driver. It invokes ISendCallback->send_callback() to pass + * the packet to the simulator. + */ + virtual void if_send_packet(const void *data, unsigned int datalen) = 0; + //virtual void if_send_packet(int if_id, const void *data, unsigned int datalen) = 0; + + /* + * called by network simulator after packet tx was sucessful. + * on Linux, this wakes up the netdev xmit queue. + */ + virtual void if_send_finish(int if_id) = 0; + + virtual void if_attach(const char *addr, const char *mask, int mtu) = 0; + virtual void add_default_gateway(const char *addr) = 0; + + /** Purely for debugging/diagnostic purposes. This returns the internal id + * of the stack instance. + */ + virtual int get_id() = 0; + + /** Should return a short one-word name of the stack. Eg. Linux 2.4.x -> + * linux24, FreeBSD 5.x -> freebsd5. This can be used to identify output + * from a stack, for example a packet trace file. */ + virtual const char *get_name() = 0; + + /** This is used so the simulator can call the stack timer_interrupt function + * the correct amount of times per second. For example, lwip has a hz of 10, + * which it returns here to say that it's timer_interrupt should be called + * 10 times a second. FreeBSD uses 100, as does Linux 2.4, while Linux 2.6 + * uses 1000. (This is often configurable in the kernel in question, also.) + */ + virtual int get_hz() = 0; + + virtual void timer_interrupt() = 0; + virtual void increment_ticks() = 0; + + virtual void buffer_size(int size) = 0; + + virtual struct INetDatagramSocket *new_udp_socket() { return NULL; } + virtual struct INetStreamSocket *new_tcp_socket() { return NULL; } + virtual struct INetStreamSocket *new_sctp_socket() { return NULL; } + + // The following I've made optional to implement for now. Eases + // integration of new features. + virtual int sysctl(const char *sysctl_name, void *oldval, size_t *oldlenp, + void *newval, size_t newlen) + { + return -1; + } + + // alternate, simpler interface. the stack cradle code is expected + // to convert the string-value to something that the stack can handle. + // The idea here is that this is a front-end to the sysctl(2) call, + // much like the sysctl(8) program. + virtual int sysctl_set(const char *name, const char *value) + { + return -1; + } + + // same as above, cradle code is expected to convert the sysctl value + // into a string. + // returns length of the string in value, i.e. retval > len: 'output truncated'. + virtual int sysctl_get(const char *name, char *value, size_t len) + { + return -1; + } + + // this tells the cradle code to put the name of sysctl number 'idx' + // into name[]. + // The idea is that this can be used to get a list of all available sysctls: + // char buf[256] + // for (i=0; sysctl_getnum(i, buf, sizeof(buf)) > 0 ;i++) + // puts(buf); + // returns -1 if idx is out of range and the length of the sysctl name otherwise. + virtual int sysctl_getnum(size_t idx, char *name, size_t len) + { + return -1; + } + + virtual void show_config() + { + ; + } + + /* Optional functions used to get and set variables for this stack */ + virtual bool get_var(const char *var, char *result, int result_len) + { + return false; + } + + virtual bool set_var(const char *var, const char *val) + { + return false; + } + + /** The level of debugging or diagnostic information to print out. This + * normally means kernel messages printed out during initialisation but + * may also include extra debugging messages that are part of NSC. */ + virtual void set_diagnostic(int level) {} + + /** Simple interface to support sending any textual command to a stack + * + * @returns 0 on success + */ + virtual int cmd(const char *) + { + return 1; + } +}; + +struct INetStreamSocket +{ + virtual ~INetStreamSocket() {} + + virtual void connect(const char *, int) = 0; + virtual void disconnect() = 0; + virtual void listen(int) = 0; + virtual int accept(INetStreamSocket **) = 0; + virtual int send_data(const void *data, int datalen) = 0; + virtual int read_data(void *buf, int *buflen) = 0; + /* We need to pass the option name in as a string here. The reason for + * this is that different operating systems you compile on will have + * different numbers defined for the constants SO_SNDBUF and so on. */ + virtual int setsockopt(char *optname, void *val, size_t valsize) = 0; + virtual void print_state(FILE *) = 0; + virtual bool is_connected() = 0; + virtual bool is_listening() = 0; + + virtual int getpeername(struct sockaddr *sa, size_t *salen) { + return -1; + } + virtual int getsockname(struct sockaddr *sa, size_t *salen) { + return -1; + } + /* Optional functions used to get and set variables for this TCP + * connection. */ + virtual bool get_var(const char *var, char *result, int result_len) + { + return false; + } + + virtual bool set_var(const char *var, const char *val) + { + return false; + } +}; + +struct INetDatagramSocket +{ + virtual ~INetDatagramSocket() {} + + virtual void set_destination(const char *, int) = 0; + virtual void send_data(const void *data, int datalen) = 0; +}; +struct ISendCallback +{ + virtual ~ISendCallback() {} + +// virtual void send_callback(int id, const void *data, unsigned int datalen) = 0; + virtual void send_callback(const void *data, unsigned int datalen) = 0; +}; + +struct IInterruptCallback +{ + virtual ~IInterruptCallback() {} + + virtual void wakeup() = 0; + virtual void gettime(unsigned int *, unsigned int *) = 0; +}; + +typedef int (*FRandom)(); +typedef INetStack *(*FCreateStack)(ISendCallback *, IInterruptCallback *, + FRandom); + +#define CREATE_STACK_FUNC(a,b,c) extern "C" INetStack *nsc_create_stack(\ + ISendCallback *a, IInterruptCallback *b, FRandom c) + +#endif diff -r 44b325571ab4 -r ae536d9e0d6d src/node/wscript --- a/src/node/wscript Wed Jul 15 14:59:44 2009 +0200 +++ b/src/node/wscript Wed Jul 15 18:46:14 2009 +0200 @@ -82,3 +82,8 @@ 'ipv6-header.h', 'ipv4-raw-socket-factory.h', ] + + if bld.env['WITH_NSC']: + node.source.append ('nsc-glue.cc') + node.source.append ('nsc-sysctl.cc') + node.uselib = 'DL'