1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * This program is free software; you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License version 2 as
5  * published by the Free Software Foundation;
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software
14  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
15  *
16  * based on earlier integration work by Tom Henderson and Sam Jansen.
17  * 2008 Florian Westphal <fw@strlen.de>
18  */
19 
20 #include "ns3/assert.h"
21 #include "ns3/log.h"
22 #include "ns3/nstime.h"
23 
24 #include "ns3/packet.h"
25 #include "ns3/node.h"
26 #include "ns3/ipv4-route.h"
27 
28 #include "ns3/object-vector.h"
29 #include "ns3/string.h"
30 #include "tcp-header.h"
31 #include "ipv4-end-point-demux.h"
32 #include "ipv4-end-point.h"
33 #include "ipv4-l3-protocol.h"
34 #include "nsc-tcp-l4-protocol.h"
35 #include "nsc-tcp-socket-impl.h"
36 #include "nsc-sysctl.h"
37 #include "nsc-tcp-socket-factory-impl.h"
38 #include "sim_interface.h"
39 
40 #include <vector>
41 #include <sstream>
42 #include <dlfcn.h>
43 #include <iomanip>
44 
45 #include <netinet/in.h>
46 #include <arpa/inet.h>
47 
48 namespace ns3 {
49 
50 NS_LOG_COMPONENT_DEFINE ("NscTcpL4Protocol");
51 
52 NS_OBJECT_ENSURE_REGISTERED (NscTcpL4Protocol);
53 
54 /* see http://www.iana.org/assignments/protocol-numbers */
55 const uint8_t NscTcpL4Protocol::PROT_NUMBER = 6;
56 
57 /**
58  * \ingroup nsctcp
59  * \brief Nsc interface implementation class.
60  */
61 class NscInterfaceImpl : public ISendCallback, public IInterruptCallback
62 {
63 public:
64   /**
65    * Constructor
66    * \param prot the NSC TCP protocol
67    */
68   NscInterfaceImpl (Ptr<NscTcpL4Protocol> prot);
69 private:
70   /**
71    * \brief Invoked by NSCs 'ethernet driver' to re-inject a packet into ns-3.
72    *
73    * A packet is an octet soup consisting of an IP Header, TCP Header
74    * and user payload, if any
75    *
76    * \param data the data
77    * \param datalen the data length
78    */
79   virtual void send_callback (const void *data, int datalen);
80   /**
81    * \brief Called by the NSC stack whenever something of interest has happened
82    *
83    * Examples: when data arrives on a socket, a listen socket
84    * has a new connection pending, etc.
85    */
86   virtual void wakeup ();
87   /**
88    * \brief Called by the Linux stack RNG initialization
89    *
90    * Its also used by the cradle code to add a timestamp to
91    * printk/printf/debug output.
92    *
93    * \param [out] sec seconds
94    * \param [out] usec microseconds
95    *
96    */
97   virtual void gettime (unsigned int *sec, unsigned int *usec);
98 private:
99   Ptr<NscTcpL4Protocol> m_prot; //!< the NSC TCP protocol
100 };
101 
NscInterfaceImpl(Ptr<NscTcpL4Protocol> prot)102 NscInterfaceImpl::NscInterfaceImpl (Ptr<NscTcpL4Protocol> prot)
103   : m_prot (prot)
104 {
105 }
106 
107 void
send_callback(const void * data,int datalen)108 NscInterfaceImpl::send_callback (const void *data, int datalen)
109 {
110   m_prot->send_callback (data, datalen);
111 }
112 void
wakeup()113 NscInterfaceImpl::wakeup ()
114 {
115   m_prot->wakeup ();
116 }
117 void
gettime(unsigned int * sec,unsigned int * usec)118 NscInterfaceImpl::gettime (unsigned int *sec, unsigned int *usec)
119 {
120   m_prot->gettime (sec,usec);
121 }
122 
123 
124 #undef NS_LOG_APPEND_CONTEXT
125 #define NS_LOG_APPEND_CONTEXT                                   \
126   if (m_node) { std::clog << Simulator::Now ().As (Time::S) << " [node " << m_node->GetId () << "] "; }
127 
128 TypeId
GetTypeId(void)129 NscTcpL4Protocol::GetTypeId (void)
130 {
131   static TypeId tid = TypeId ("ns3::NscTcpL4Protocol")
132     .SetParent<IpL4Protocol> ()
133     .SetGroupName ("Internet")
134     .AddConstructor<NscTcpL4Protocol>()
135     .AddAttribute ("SocketList", "The list of sockets associated to this protocol.",
136                    ObjectVectorValue (),
137                    MakeObjectVectorAccessor (&NscTcpL4Protocol::m_sockets),
138                    MakeObjectVectorChecker<NscTcpSocketImpl> ())
139     .AddAttribute ("Library",
140                    "Set the linux library to be used to create the stack",
141                    TypeId::ATTR_GET|TypeId::ATTR_CONSTRUCT,
142                    StringValue ("liblinux2.6.26.so"),
143                    MakeStringAccessor (&NscTcpL4Protocol::GetNscLibrary,&NscTcpL4Protocol::SetNscLibrary),
144                    MakeStringChecker ())
145   ;
146   return tid;
147 }
148 
149 /**
150  * \brief External Random number generator
151  *
152  * \todo make it random...
153  *
154  * \returns a random number
155  */
external_rand()156 int external_rand ()
157 {
158   return 1;
159 }
160 
NscTcpL4Protocol()161 NscTcpL4Protocol::NscTcpL4Protocol ()
162   : m_endPoints (new Ipv4EndPointDemux ()),
163     m_nscStack (0),
164     m_nscInterface (new NscInterfaceImpl (this)),
165     m_softTimer (Timer::CANCEL_ON_DESTROY)
166 {
167   m_dlopenHandle = NULL;
168   NS_LOG_LOGIC ("Made a NscTcpL4Protocol "<<this);
169 }
170 
~NscTcpL4Protocol()171 NscTcpL4Protocol::~NscTcpL4Protocol ()
172 {
173   NS_LOG_FUNCTION (this);
174   dlclose (m_dlopenHandle);
175 }
176 
177 void
SetNscLibrary(const std::string & soname)178 NscTcpL4Protocol::SetNscLibrary (const std::string &soname)
179 {
180   if (soname!="")
181     {
182       m_nscLibrary = soname;
183       NS_ASSERT (!m_dlopenHandle);
184       m_dlopenHandle = dlopen (soname.c_str (), RTLD_NOW);
185       if (m_dlopenHandle == NULL)
186         NS_FATAL_ERROR (dlerror ());
187     }
188 }
189 
190 std::string
GetNscLibrary() const191 NscTcpL4Protocol::GetNscLibrary () const
192 {
193   return m_nscLibrary;
194 }
195 void
SetNode(Ptr<Node> node)196 NscTcpL4Protocol::SetNode (Ptr<Node> node)
197 {
198   m_node = node;
199 
200   if (m_nscStack)
201     { // stack has already been loaded...
202       return;
203     }
204 
205   NS_ASSERT (m_dlopenHandle);
206 
207   FCreateStack create = (FCreateStack)dlsym (m_dlopenHandle, "nsc_create_stack");
208   NS_ASSERT (create);
209   m_nscStack = create (m_nscInterface, m_nscInterface, external_rand);
210   int hzval = m_nscStack->get_hz ();
211 
212   NS_ASSERT (hzval > 0);
213 
214   m_softTimer.SetFunction (&NscTcpL4Protocol::SoftInterrupt, this);
215   m_softTimer.SetDelay (MilliSeconds (1000/hzval));
216   m_nscStack->init (hzval);
217   // This enables stack and NSC debug messages
218   // m_nscStack->set_diagnostic(1000);
219 
220   Ptr<Ns3NscStack> nscStack = Create<Ns3NscStack> ();
221   nscStack->SetStack (m_nscStack);
222   node->AggregateObject (nscStack);
223 
224   m_softTimer.Schedule ();
225 
226   // its likely no ns-3 interface exits at this point, so
227   // we dealy adding the nsc interface until the start of the simulation.
228   Simulator::ScheduleNow (&NscTcpL4Protocol::AddInterface, this);
229 }
230 
231 void
NotifyNewAggregate()232 NscTcpL4Protocol::NotifyNewAggregate ()
233 {
234   if (m_node == 0)
235     {
236       Ptr<Node>node = this->GetObject<Node> ();
237       if (node != 0)
238         {
239           Ptr<Ipv4L3Protocol> ipv4 = this->GetObject<Ipv4L3Protocol> ();
240           if (ipv4 != 0 && m_downTarget.IsNull ())
241             {
242               this->SetNode (node);
243               ipv4->Insert (this);
244               Ptr<NscTcpSocketFactoryImpl> tcpFactory = CreateObject<NscTcpSocketFactoryImpl> ();
245               tcpFactory->SetTcp (this);
246               node->AggregateObject (tcpFactory);
247               this->SetDownTarget (MakeCallback (&Ipv4L3Protocol::Send, ipv4));
248             }
249         }
250     }
251   IpL4Protocol::NotifyNewAggregate ();
252 }
253 
254 int
GetProtocolNumber(void) const255 NscTcpL4Protocol::GetProtocolNumber (void) const
256 {
257   return PROT_NUMBER;
258 }
259 int
GetVersion(void) const260 NscTcpL4Protocol::GetVersion (void) const
261 {
262   return 2;
263 }
264 
265 void
DoDispose(void)266 NscTcpL4Protocol::DoDispose (void)
267 {
268   NS_LOG_FUNCTION (this);
269 
270   for (std::vector<Ptr<NscTcpSocketImpl> >::iterator i = m_sockets.begin (); i != m_sockets.end (); i++)
271     {
272       *i = 0;
273     }
274   m_sockets.clear ();
275 
276 
277   if (m_endPoints != 0)
278     {
279       delete m_endPoints;
280       m_endPoints = 0;
281     }
282   m_node = 0;
283   delete m_nscInterface;
284   m_nscInterface = 0;
285   m_downTarget.Nullify ();
286   IpL4Protocol::DoDispose ();
287 }
288 
289 Ptr<Socket>
CreateSocket(void)290 NscTcpL4Protocol::CreateSocket (void)
291 {
292   NS_LOG_FUNCTION (this);
293 
294   Ptr<NscTcpSocketImpl> socket = CreateObject<NscTcpSocketImpl> ();
295   socket->SetNode (m_node);
296   socket->SetTcp (this);
297   m_sockets.push_back (socket);
298   return socket;
299 }
300 
301 Ipv4EndPoint *
Allocate(void)302 NscTcpL4Protocol::Allocate (void)
303 {
304   NS_LOG_FUNCTION (this);
305   return m_endPoints->Allocate ();
306 }
307 
308 Ipv4EndPoint *
Allocate(Ipv4Address address)309 NscTcpL4Protocol::Allocate (Ipv4Address address)
310 {
311   NS_LOG_FUNCTION (this << address);
312   return m_endPoints->Allocate (address);
313 }
314 
315 Ipv4EndPoint *
Allocate(Ptr<NetDevice> boundNetDevice,uint16_t port)316 NscTcpL4Protocol::Allocate (Ptr<NetDevice> boundNetDevice, uint16_t port)
317 {
318   NS_LOG_FUNCTION (this << boundNetDevice << port);
319   return m_endPoints->Allocate (boundNetDevice, port);
320 }
321 
322 Ipv4EndPoint *
Allocate(Ptr<NetDevice> boundNetDevice,Ipv4Address address,uint16_t port)323 NscTcpL4Protocol::Allocate (Ptr<NetDevice> boundNetDevice, Ipv4Address address, uint16_t port)
324 {
325   NS_LOG_FUNCTION (this << boundNetDevice << address << port);
326   return m_endPoints->Allocate (boundNetDevice, address, port);
327 }
328 
329 Ipv4EndPoint *
Allocate(Ptr<NetDevice> boundNetDevice,Ipv4Address localAddress,uint16_t localPort,Ipv4Address peerAddress,uint16_t peerPort)330 NscTcpL4Protocol::Allocate (Ptr<NetDevice> boundNetDevice,
331                             Ipv4Address localAddress, uint16_t localPort,
332                             Ipv4Address peerAddress, uint16_t peerPort)
333 {
334   NS_LOG_FUNCTION (this << boundNetDevice << localAddress << localPort << peerAddress << peerPort);
335   return m_endPoints->Allocate (boundNetDevice,
336                                 localAddress, localPort,
337                                 peerAddress, peerPort);
338 }
339 
340 void
DeAllocate(Ipv4EndPoint * endPoint)341 NscTcpL4Protocol::DeAllocate (Ipv4EndPoint *endPoint)
342 {
343   NS_LOG_FUNCTION (this << endPoint);
344   // NSC m_endPoints->DeAllocate (endPoint);
345 }
346 
347 IpL4Protocol::RxStatus
Receive(Ptr<Packet> packet,Ipv4Header const & header,Ptr<Ipv4Interface> incomingInterface)348 NscTcpL4Protocol::Receive (Ptr<Packet> packet,
349                            Ipv4Header const &header,
350                            Ptr<Ipv4Interface> incomingInterface)
351 {
352   NS_LOG_FUNCTION (this << packet << header << incomingInterface);
353   Ipv4Header ipHeader;
354   uint32_t packetSize = packet->GetSize ();
355 
356   // The way things work at the moment, the IP header has been removed
357   // by the ns-3 IPv4 processing code. However, the NSC stack expects
358   // a complete IP packet, so we add the IP header back.
359   // Since the original header is already gone, we create a new one
360   // based on the information we have.
361   ipHeader.SetSource (header.GetSource ());
362   ipHeader.SetDestination (header.GetDestination ());
363   ipHeader.SetProtocol (PROT_NUMBER);
364   ipHeader.SetPayloadSize (packetSize);
365   ipHeader.SetTtl (1);
366   // all NSC stacks check the IP checksum
367   ipHeader.EnableChecksum ();
368 
369   packet->AddHeader (ipHeader);
370   packetSize = packet->GetSize ();
371 
372   uint8_t *buf = new uint8_t[packetSize];
373   packet->CopyData (buf, packetSize);
374   const uint8_t *data = const_cast<uint8_t *>(buf);
375 
376   // deliver complete packet to the NSC network stack
377   m_nscStack->if_receive_packet (0, data, packetSize);
378   delete[] buf;
379 
380   wakeup ();
381   return IpL4Protocol::RX_OK;
382 }
383 
384 IpL4Protocol::RxStatus
Receive(Ptr<Packet>,Ipv6Header const &,Ptr<Ipv6Interface>)385 NscTcpL4Protocol::Receive(Ptr<Packet>, Ipv6Header const &, Ptr<Ipv6Interface>)
386 {
387   return IpL4Protocol::RX_ENDPOINT_UNREACH;
388 }
389 
SoftInterrupt(void)390 void NscTcpL4Protocol::SoftInterrupt (void)
391 {
392   m_nscStack->timer_interrupt ();
393   m_nscStack->increment_ticks ();
394   m_softTimer.Schedule ();
395 }
396 
send_callback(const void * data,int datalen)397 void NscTcpL4Protocol::send_callback (const void* data, int datalen)
398 {
399   Ptr<Packet> p;
400   uint32_t ipv4Saddr, ipv4Daddr;
401 
402   NS_ASSERT (datalen > 20);
403 
404 
405   // create packet, without IP header. The TCP header is not touched.
406   // Not using the IP header makes integration easier, but it destroys
407   // eg. ECN.
408   const uint8_t *rawdata = reinterpret_cast<const uint8_t *>(data);
409   rawdata += 20; // skip IP header. IP options aren't supported at this time.
410   datalen -= 20;
411   p = Create<Packet> (rawdata, datalen);
412 
413   // we need the real source/destination ipv4 addresses for Send ().
414   const uint32_t *ipheader = reinterpret_cast<const uint32_t *>(data);
415   ipv4Saddr = *(ipheader+3);
416   ipv4Daddr = *(ipheader+4);
417 
418   Ipv4Address saddr (ntohl (ipv4Saddr));
419   Ipv4Address daddr (ntohl (ipv4Daddr));
420 
421   Ptr<Ipv4L3Protocol> ipv4 = m_node->GetObject<Ipv4L3Protocol> ();
422   NS_ASSERT_MSG (ipv4, "nsc callback invoked, but node has no ipv4 object");
423 
424   m_downTarget (p, saddr, daddr, PROT_NUMBER, 0);
425   m_nscStack->if_send_finish (0);
426 }
427 
wakeup()428 void NscTcpL4Protocol::wakeup ()
429 {
430   // \todo
431   // this should schedule a timer to read from all tcp sockets now... this is
432   // an indication that data might be waiting on the socket
433 
434   Ipv4EndPointDemux::EndPoints endPoints = m_endPoints->GetAllEndPoints ();
435   for (Ipv4EndPointDemux::EndPointsI endPoint = endPoints.begin ();
436        endPoint != endPoints.end (); endPoint++) {
437       // NSC HACK: (ab)use TcpSocket::ForwardUp for signalling
438       (*endPoint)->ForwardUp (NULL, Ipv4Header (), 0, 0);
439     }
440 }
441 
gettime(unsigned int * sec,unsigned int * usec)442 void NscTcpL4Protocol::gettime (unsigned int* sec, unsigned int* usec)
443 {
444   // Only used by the Linux network stack, e.g. during ISN generation
445   // and in the kernel rng initialization routine. Also used in Linux
446   // printk output.
447   Time t = Simulator::Now ();
448   int64_t us = t.GetMicroSeconds ();
449   *sec = us / (1000*1000);
450   *usec = us - *sec * (1000*1000);
451 }
452 
453 
AddInterface(void)454 void NscTcpL4Protocol::AddInterface (void)
455 {
456   Ptr<Ipv4> ip = m_node->GetObject<Ipv4> ();
457   const uint32_t nInterfaces = ip->GetNInterfaces ();
458 
459   NS_ASSERT_MSG (nInterfaces <= 2, "nsc does not support multiple interfaces per node");
460 
461   // start from 1, ignore the loopback interface (HACK)
462   // we really don't need the loop, but its here to illustrate
463   // how things _should_ be (once nsc can deal with multiple interfaces...)
464   for (uint32_t i = 1; i < nInterfaces; i++)
465     {
466       Ipv4InterfaceAddress ifAddr = ip->GetAddress (i, 0);
467       Ipv4Address addr = ifAddr.GetLocal ();
468       Ipv4Mask mask = ifAddr.GetMask ();
469       uint16_t mtu = ip->GetMtu (i);
470 
471       std::ostringstream addrOss, maskOss;
472 
473       addr.Print (addrOss);
474       mask.Print (maskOss);
475 
476       NS_LOG_LOGIC ("if_attach " << addrOss.str ().c_str () << " " << maskOss.str ().c_str () << " " << mtu);
477 
478       std::string addrStr = addrOss.str ();
479       std::string maskStr = maskOss.str ();
480       const char* addrCStr = addrStr.c_str ();
481       const char* maskCStr = maskStr.c_str ();
482       m_nscStack->if_attach (addrCStr, maskCStr, mtu);
483 
484       if (i == 1)
485         {
486           // The NSC stack requires a default gateway and only supports
487           // single-interface nodes.  The below is a hack, but
488           // it turns out that we can pass the interface address to nsc as
489           // a default gateway.  Bug 1398 has been opened to track this
490           // issue (NSC's limitation to single-interface nodes)
491           //
492           // Previous versions of this code tried to assign the "next"
493           // IP address of the subnet but this was found to fail for
494           // some use cases in /30 subnets.
495 
496           // \todo \bugid{1398} NSC's limitation to single-interface nodes
497           m_nscStack->add_default_gateway (addrOss.str ().c_str ());
498         }
499     }
500 }
501 
502 void
SetDownTarget(IpL4Protocol::DownTargetCallback callback)503 NscTcpL4Protocol::SetDownTarget (IpL4Protocol::DownTargetCallback callback)
504 {
505   m_downTarget = callback;
506 }
507 
508 void
SetDownTarget6(IpL4Protocol::DownTargetCallback6 callback)509 NscTcpL4Protocol::SetDownTarget6 (IpL4Protocol::DownTargetCallback6 callback)
510 {
511 }
512 
513 IpL4Protocol::DownTargetCallback
GetDownTarget(void) const514 NscTcpL4Protocol::GetDownTarget (void) const
515 {
516   return m_downTarget;
517 }
518 
519 IpL4Protocol::DownTargetCallback6
GetDownTarget6(void) const520 NscTcpL4Protocol::GetDownTarget6 (void) const
521 {
522   return (IpL4Protocol::DownTargetCallback6)0;
523 }
524 
525 } // namespace ns3
526 
527