src/node/nsc-glue.cc
changeset 4685 ae536d9e0d6d
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/node/nsc-glue.cc	Wed Jul 15 18:46:14 2009 +0200
     1.3 @@ -0,0 +1,236 @@
     1.4 +#include <dlfcn.h>
     1.5 +
     1.6 +#include "ns3/boolean.h"
     1.7 +#include "ns3/log.h"
     1.8 +#include "ns3/ipv4-l3-protocol.h"
     1.9 +
    1.10 +#include "ns3/ipv4-interface.h"
    1.11 +#include "ns3/object.h"
    1.12 +#include "ns3/packet.h"
    1.13 +#include "ns3/ptr.h"
    1.14 +#include "ns3/nstime.h"
    1.15 +
    1.16 +#include "nsc-glue.h"
    1.17 +#include "node.h"
    1.18 +
    1.19 +#include <netinet/ip.h>
    1.20 +#include <arpa/inet.h>
    1.21 +
    1.22 +namespace ns3 {
    1.23 +
    1.24 +NS_OBJECT_ENSURE_REGISTERED (NscGlue);
    1.25 +
    1.26 +TypeId
    1.27 +NscGlue::GetTypeId (void)
    1.28 +{
    1.29 +  static TypeId tid = TypeId ("ns3::NscGlue")
    1.30 +    .SetParent <Object> ()
    1.31 +    ;
    1.32 +  return tid;
    1.33 +}
    1.34 +
    1.35 +NscGlue::NscGlue(void)
    1.36 +	: m_wakeupCallbacks(0),
    1.37 +	  m_dlopenHandle(0)
    1.38 +{
    1.39 +}
    1.40 +
    1.41 +void
    1.42 +NscGlue::SetNode(Ptr<Node> n)
    1.43 +{
    1.44 +  m_node = n;
    1.45 +}
    1.46 +
    1.47 +void
    1.48 +NscGlue::PassPacketToNsc (Ptr<const Packet> packet, int idx)
    1.49 +{
    1.50 +  uint32_t packetSize = packet->GetSize();
    1.51 +  const uint8_t *data = const_cast<uint8_t *>(packet->PeekData());
    1.52 +
    1.53 +  // deliver complete packet to the NSC network stack
    1.54 +  m_nscStack->if_receive_packet(idx, data, packetSize);
    1.55 +  wakeup ();
    1.56 +}
    1.57 +
    1.58 +bool
    1.59 +NscGlue::IsNscProtocol (uint16_t proto)
    1.60 +{
    1.61 +  return proto == 0x0800; // NSC can only handle ipv4 at the moment.
    1.62 +}
    1.63 +
    1.64 +static int external_rand(void)
    1.65 +{
    1.66 +  return 1; // XXX: check which NSC stacks actually use this
    1.67 +}
    1.68 +
    1.69 +void
    1.70 +NscGlue::SetNscLibrary(const std::string &soname)
    1.71 +{
    1.72 +  NS_ASSERT(!m_dlopenHandle);
    1.73 +  m_dlopenHandle = dlopen(soname.c_str (), RTLD_NOW);
    1.74 +  if (m_dlopenHandle == NULL)
    1.75 +    NS_FATAL_ERROR (dlerror());
    1.76 +
    1.77 +  FCreateStack create = (FCreateStack)dlsym(m_dlopenHandle, "nsc_create_stack");
    1.78 +
    1.79 +  m_nscStack = create(this, this, external_rand);
    1.80 +  int hzval = m_nscStack->get_hz();
    1.81 +
    1.82 +  NS_ASSERT(hzval > 0);
    1.83 +
    1.84 +  m_softTimer.SetFunction (&NscGlue::SoftRtcInterrupt, this);
    1.85 +  m_softTimer.SetDelay (MilliSeconds (1000/hzval));
    1.86 +  // This enables stack and NSC debug messages
    1.87 +  m_nscStack->set_diagnostic(10);
    1.88 +  m_nscStack->init(hzval);
    1.89 +
    1.90 +  Ptr<Ns3NscStack> nscStack = Create<Ns3NscStack> ();
    1.91 +  nscStack->SetStack (m_nscStack);
    1.92 +  m_node->AggregateObject (nscStack);
    1.93 +
    1.94 +  m_softTimer.Schedule ();
    1.95 +  // its likely no ns-3 interface exits at this point, so
    1.96 +  // we delay adding the nsc interface until the start of the simulation.
    1.97 +  Simulator::ScheduleNow(&NscGlue::AddIface, this);
    1.98 +
    1.99 +  m_nscLibrary = soname;
   1.100 +}
   1.101 +
   1.102 +std::string
   1.103 +NscGlue::GetNscLibrary () const
   1.104 +{
   1.105 +  return m_nscLibrary;
   1.106 +}
   1.107 +
   1.108 +
   1.109 +void NscGlue::wakeup()
   1.110 +{
   1.111 +  // TODO
   1.112 +  // this should schedule a timer to read from all tcp sockets now... this is
   1.113 +  // an indication that data might be waiting on the socket
   1.114 +  for (std::list<Callback<void> >::iterator i = m_wakeupCallbacks.begin ();
   1.115 +	i != m_wakeupCallbacks.end (); i++)
   1.116 +     {
   1.117 +        Callback<void> cb = *i;
   1.118 +	cb ();
   1.119 +     }
   1.120 +}
   1.121 +
   1.122 +void NscGlue::SoftRtcInterrupt (void)
   1.123 +{
   1.124 +  m_nscStack->timer_interrupt ();
   1.125 +  m_nscStack->increment_ticks ();
   1.126 +  m_softTimer.Schedule ();
   1.127 +}
   1.128 +
   1.129 +void NscGlue::gettime(unsigned int* sec, unsigned int* usec)
   1.130 +{
   1.131 +  // Only used by the Linux network stack, e.g. during ISN generation
   1.132 +  // and in the kernel rng initialization routine. Also used in Linux
   1.133 +  // printk output.
   1.134 +  Time t = Simulator::Now ();
   1.135 +  int64_t us = t.GetMicroSeconds ();
   1.136 +  *sec = us / (1000*1000);
   1.137 +  *usec = us - *sec * (1000*1000);
   1.138 +}
   1.139 +
   1.140 +#ifdef NSC_NEXT
   1.141 +void NscGlue::send_callback(int idx, const void* data, unsigned int datalen)
   1.142 +#else
   1.143 +void NscGlue::send_callback(/* int idx,*/ const void* data, unsigned int datalen)
   1.144 +#endif
   1.145 +{
   1.146 +#ifndef NSC_NEXT
   1.147 + int idx = 0;
   1.148 +#endif
   1.149 +  Ptr<Packet> p;
   1.150 +  uint32_t ipv4Daddr;
   1.151 +
   1.152 +  NS_ASSERT(datalen > 20);
   1.153 +
   1.154 +  // FIXME: XXX: This won't really work when NSC is able to use
   1.155 +  // L3 protocols other than AF_INET. We really really really
   1.156 +  // should be able to do all routing decisions inside nsc and just
   1.157 +  // pass packets to whatever network interface without looking at its contents.
   1.158 +  const uint8_t *rawdata = reinterpret_cast<const uint8_t *>(data);
   1.159 +  
   1.160 +  p = Create<Packet> (rawdata, datalen);
   1.161 + 
   1.162 +  // we need the destination ipv4 address for Send ().
   1.163 +  const uint32_t *ipheader = reinterpret_cast<const uint32_t *>(data);
   1.164 +
   1.165 +  ipv4Daddr = *(ipheader+4);
   1.166 +
   1.167 +  Ipv4Address daddr(ntohl(ipv4Daddr));
   1.168 +
   1.169 +  Ptr<Ipv4L3Protocol> ipv4 = m_node->GetObject<Ipv4L3Protocol> ();
   1.170 +  NS_ASSERT_MSG (ipv4, "nsc callback invoked, but node has no ipv4 object");
   1.171 +  // FIXME: do _all_ routing via NSC and provide a ns3-nsc mapping that
   1.172 +  // tells us which ns-3 interface the nsc interface "idx" is corresponding to.
   1.173 +//NS_LOG_LOGIC ("ns3: xmit via device number " << idx);
   1.174 +  Ptr<Ipv4Interface> outInterface = ipv4->GetInterface ( idx + 1);
   1.175 +
   1.176 +  NS_ASSERT (outInterface);
   1.177 +  outInterface->Send (p, daddr);
   1.178 +  m_nscStack->if_send_finish(0);
   1.179 +}
   1.180 +
   1.181 +
   1.182 +void NscGlue::RegisterWakeupCallback(Callback<void> cb)
   1.183 +{
   1.184 +  m_wakeupCallbacks.push_back (cb);
   1.185 +}
   1.186 +
   1.187 +void NscGlue::AddIface(void)
   1.188 +{
   1.189 +    Ptr<Ipv4> ip = m_node->GetObject<Ipv4> ();
   1.190 +
   1.191 +    const uint32_t nInterfaces = ip->GetNInterfaces ();
   1.192 +    // start from 1, ignore the loopback interface (HACK)
   1.193 +
   1.194 +    for (uint32_t i = 1; i < nInterfaces; i++)
   1.195 +    {
   1.196 +      Ipv4InterfaceAddress ifAddr = ip->GetAddress (i, 0);
   1.197 +      Ipv4Address addr = ifAddr.GetLocal ();
   1.198 +      Ipv4Mask mask = ifAddr.GetMask ();
   1.199 +
   1.200 +      uint16_t mtu = ip->GetMtu (i);
   1.201 +
   1.202 +      std::ostringstream addrOss, maskOss;
   1.203 +
   1.204 +      addr.Print(addrOss);
   1.205 +      mask.Print(maskOss);
   1.206 +
   1.207 +//    NS_LOG_LOGIC ("if_attach " << addrOss.str().c_str() << " " << maskOss.str().c_str() << " " << mtu);
   1.208 +
   1.209 +      std::string addrStr = addrOss.str();
   1.210 +      std::string maskStr = maskOss.str();
   1.211 +      const char* addrCStr = addrStr.c_str();
   1.212 +      const char* maskCStr = maskStr.c_str();
   1.213 +      NS_ASSERT_MSG (m_nscStack, "m_nscStackError");
   1.214 +      m_nscStack->if_attach(addrCStr, maskCStr, mtu);
   1.215 +
   1.216 +      if (i == 1)
   1.217 +      {
   1.218 +        // We need to come up with a default gateway here. Can't guarantee this to be
   1.219 +        // correct really...
   1.220 +
   1.221 +        uint8_t addrBytes[4];
   1.222 +        addr.Serialize(addrBytes);
   1.223 +
   1.224 +        // XXX: this is all a bit of a horrible hack
   1.225 +        //
   1.226 +        // Just increment the last octet, this gives a decent chance of this being
   1.227 +        // 'enough'.
   1.228 +        //
   1.229 +        // All we need is another address on the same network as the interface. This
   1.230 +        // will force the stack to output the packet out of the network interface.
   1.231 +        addrBytes[3]++;
   1.232 +        addr.Deserialize(addrBytes);
   1.233 +        addrOss.str("");
   1.234 +        addr.Print(addrOss);
   1.235 +        m_nscStack->add_default_gateway(addrOss.str().c_str());
   1.236 +      }
   1.237 +   }
   1.238 +}
   1.239 +} // namespace ns3