src/node/nsc-glue.cc
author Florian Westphal <fw@strlen.de>
Wed Jul 15 18:46:14 2009 +0200 (2009-07-15)
changeset 4685 ae536d9e0d6d
permissions -rw-r--r--
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.
     1 #include <dlfcn.h>
     2 
     3 #include "ns3/boolean.h"
     4 #include "ns3/log.h"
     5 #include "ns3/ipv4-l3-protocol.h"
     6 
     7 #include "ns3/ipv4-interface.h"
     8 #include "ns3/object.h"
     9 #include "ns3/packet.h"
    10 #include "ns3/ptr.h"
    11 #include "ns3/nstime.h"
    12 
    13 #include "nsc-glue.h"
    14 #include "node.h"
    15 
    16 #include <netinet/ip.h>
    17 #include <arpa/inet.h>
    18 
    19 namespace ns3 {
    20 
    21 NS_OBJECT_ENSURE_REGISTERED (NscGlue);
    22 
    23 TypeId
    24 NscGlue::GetTypeId (void)
    25 {
    26   static TypeId tid = TypeId ("ns3::NscGlue")
    27     .SetParent <Object> ()
    28     ;
    29   return tid;
    30 }
    31 
    32 NscGlue::NscGlue(void)
    33 	: m_wakeupCallbacks(0),
    34 	  m_dlopenHandle(0)
    35 {
    36 }
    37 
    38 void
    39 NscGlue::SetNode(Ptr<Node> n)
    40 {
    41   m_node = n;
    42 }
    43 
    44 void
    45 NscGlue::PassPacketToNsc (Ptr<const Packet> packet, int idx)
    46 {
    47   uint32_t packetSize = packet->GetSize();
    48   const uint8_t *data = const_cast<uint8_t *>(packet->PeekData());
    49 
    50   // deliver complete packet to the NSC network stack
    51   m_nscStack->if_receive_packet(idx, data, packetSize);
    52   wakeup ();
    53 }
    54 
    55 bool
    56 NscGlue::IsNscProtocol (uint16_t proto)
    57 {
    58   return proto == 0x0800; // NSC can only handle ipv4 at the moment.
    59 }
    60 
    61 static int external_rand(void)
    62 {
    63   return 1; // XXX: check which NSC stacks actually use this
    64 }
    65 
    66 void
    67 NscGlue::SetNscLibrary(const std::string &soname)
    68 {
    69   NS_ASSERT(!m_dlopenHandle);
    70   m_dlopenHandle = dlopen(soname.c_str (), RTLD_NOW);
    71   if (m_dlopenHandle == NULL)
    72     NS_FATAL_ERROR (dlerror());
    73 
    74   FCreateStack create = (FCreateStack)dlsym(m_dlopenHandle, "nsc_create_stack");
    75 
    76   m_nscStack = create(this, this, external_rand);
    77   int hzval = m_nscStack->get_hz();
    78 
    79   NS_ASSERT(hzval > 0);
    80 
    81   m_softTimer.SetFunction (&NscGlue::SoftRtcInterrupt, this);
    82   m_softTimer.SetDelay (MilliSeconds (1000/hzval));
    83   // This enables stack and NSC debug messages
    84   m_nscStack->set_diagnostic(10);
    85   m_nscStack->init(hzval);
    86 
    87   Ptr<Ns3NscStack> nscStack = Create<Ns3NscStack> ();
    88   nscStack->SetStack (m_nscStack);
    89   m_node->AggregateObject (nscStack);
    90 
    91   m_softTimer.Schedule ();
    92   // its likely no ns-3 interface exits at this point, so
    93   // we delay adding the nsc interface until the start of the simulation.
    94   Simulator::ScheduleNow(&NscGlue::AddIface, this);
    95 
    96   m_nscLibrary = soname;
    97 }
    98 
    99 std::string
   100 NscGlue::GetNscLibrary () const
   101 {
   102   return m_nscLibrary;
   103 }
   104 
   105 
   106 void NscGlue::wakeup()
   107 {
   108   // TODO
   109   // this should schedule a timer to read from all tcp sockets now... this is
   110   // an indication that data might be waiting on the socket
   111   for (std::list<Callback<void> >::iterator i = m_wakeupCallbacks.begin ();
   112 	i != m_wakeupCallbacks.end (); i++)
   113      {
   114         Callback<void> cb = *i;
   115 	cb ();
   116      }
   117 }
   118 
   119 void NscGlue::SoftRtcInterrupt (void)
   120 {
   121   m_nscStack->timer_interrupt ();
   122   m_nscStack->increment_ticks ();
   123   m_softTimer.Schedule ();
   124 }
   125 
   126 void NscGlue::gettime(unsigned int* sec, unsigned int* usec)
   127 {
   128   // Only used by the Linux network stack, e.g. during ISN generation
   129   // and in the kernel rng initialization routine. Also used in Linux
   130   // printk output.
   131   Time t = Simulator::Now ();
   132   int64_t us = t.GetMicroSeconds ();
   133   *sec = us / (1000*1000);
   134   *usec = us - *sec * (1000*1000);
   135 }
   136 
   137 #ifdef NSC_NEXT
   138 void NscGlue::send_callback(int idx, const void* data, unsigned int datalen)
   139 #else
   140 void NscGlue::send_callback(/* int idx,*/ const void* data, unsigned int datalen)
   141 #endif
   142 {
   143 #ifndef NSC_NEXT
   144  int idx = 0;
   145 #endif
   146   Ptr<Packet> p;
   147   uint32_t ipv4Daddr;
   148 
   149   NS_ASSERT(datalen > 20);
   150 
   151   // FIXME: XXX: This won't really work when NSC is able to use
   152   // L3 protocols other than AF_INET. We really really really
   153   // should be able to do all routing decisions inside nsc and just
   154   // pass packets to whatever network interface without looking at its contents.
   155   const uint8_t *rawdata = reinterpret_cast<const uint8_t *>(data);
   156   
   157   p = Create<Packet> (rawdata, datalen);
   158  
   159   // we need the destination ipv4 address for Send ().
   160   const uint32_t *ipheader = reinterpret_cast<const uint32_t *>(data);
   161 
   162   ipv4Daddr = *(ipheader+4);
   163 
   164   Ipv4Address daddr(ntohl(ipv4Daddr));
   165 
   166   Ptr<Ipv4L3Protocol> ipv4 = m_node->GetObject<Ipv4L3Protocol> ();
   167   NS_ASSERT_MSG (ipv4, "nsc callback invoked, but node has no ipv4 object");
   168   // FIXME: do _all_ routing via NSC and provide a ns3-nsc mapping that
   169   // tells us which ns-3 interface the nsc interface "idx" is corresponding to.
   170 //NS_LOG_LOGIC ("ns3: xmit via device number " << idx);
   171   Ptr<Ipv4Interface> outInterface = ipv4->GetInterface ( idx + 1);
   172 
   173   NS_ASSERT (outInterface);
   174   outInterface->Send (p, daddr);
   175   m_nscStack->if_send_finish(0);
   176 }
   177 
   178 
   179 void NscGlue::RegisterWakeupCallback(Callback<void> cb)
   180 {
   181   m_wakeupCallbacks.push_back (cb);
   182 }
   183 
   184 void NscGlue::AddIface(void)
   185 {
   186     Ptr<Ipv4> ip = m_node->GetObject<Ipv4> ();
   187 
   188     const uint32_t nInterfaces = ip->GetNInterfaces ();
   189     // start from 1, ignore the loopback interface (HACK)
   190 
   191     for (uint32_t i = 1; i < nInterfaces; i++)
   192     {
   193       Ipv4InterfaceAddress ifAddr = ip->GetAddress (i, 0);
   194       Ipv4Address addr = ifAddr.GetLocal ();
   195       Ipv4Mask mask = ifAddr.GetMask ();
   196 
   197       uint16_t mtu = ip->GetMtu (i);
   198 
   199       std::ostringstream addrOss, maskOss;
   200 
   201       addr.Print(addrOss);
   202       mask.Print(maskOss);
   203 
   204 //    NS_LOG_LOGIC ("if_attach " << addrOss.str().c_str() << " " << maskOss.str().c_str() << " " << mtu);
   205 
   206       std::string addrStr = addrOss.str();
   207       std::string maskStr = maskOss.str();
   208       const char* addrCStr = addrStr.c_str();
   209       const char* maskCStr = maskStr.c_str();
   210       NS_ASSERT_MSG (m_nscStack, "m_nscStackError");
   211       m_nscStack->if_attach(addrCStr, maskCStr, mtu);
   212 
   213       if (i == 1)
   214       {
   215         // We need to come up with a default gateway here. Can't guarantee this to be
   216         // correct really...
   217 
   218         uint8_t addrBytes[4];
   219         addr.Serialize(addrBytes);
   220 
   221         // XXX: this is all a bit of a horrible hack
   222         //
   223         // Just increment the last octet, this gives a decent chance of this being
   224         // 'enough'.
   225         //
   226         // All we need is another address on the same network as the interface. This
   227         // will force the stack to output the packet out of the network interface.
   228         addrBytes[3]++;
   229         addr.Deserialize(addrBytes);
   230         addrOss.str("");
   231         addr.Print(addrOss);
   232         m_nscStack->add_default_gateway(addrOss.str().c_str());
   233       }
   234    }
   235 }
   236 } // namespace ns3