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