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