A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
nsc-tcp-l4-protocol.cc
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 NS_LOG_COMPONENT_DEFINE ("NscTcpL4Protocol");
49 
50 namespace ns3 {
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 
58 {
59 public:
61 private:
62  virtual void send_callback (const void *data, int datalen);
63  virtual void wakeup ();
64  virtual void gettime (unsigned int *, unsigned int *);
65 private:
66  Ptr<NscTcpL4Protocol> m_prot;
67 };
68 
69 NscInterfaceImpl::NscInterfaceImpl (Ptr<NscTcpL4Protocol> prot)
70  : m_prot (prot)
71 {
72 }
73 
74 void
75 NscInterfaceImpl::send_callback (const void *data, int datalen)
76 {
77  m_prot->send_callback (data, datalen);
78 }
79 void
80 NscInterfaceImpl::wakeup ()
81 {
82  m_prot->wakeup ();
83 }
84 void
85 NscInterfaceImpl::gettime (unsigned int *sec, unsigned int *usec)
86 {
87  m_prot->gettime (sec,usec);
88 }
89 
90 
91 #undef NS_LOG_APPEND_CONTEXT
92 #define NS_LOG_APPEND_CONTEXT \
93  if (m_node) { std::clog << Simulator::Now ().GetSeconds () << " [node " << m_node->GetId () << "] "; }
94 
95 TypeId
96 NscTcpL4Protocol::GetTypeId (void)
97 {
98  static TypeId tid = TypeId ("ns3::NscTcpL4Protocol")
99  .SetParent<IpL4Protocol> ()
100  .AddConstructor<NscTcpL4Protocol>()
101  .AddAttribute ("SocketList", "The list of sockets associated to this protocol.",
102  ObjectVectorValue (),
103  MakeObjectVectorAccessor (&NscTcpL4Protocol::m_sockets),
104  MakeObjectVectorChecker<NscTcpSocketImpl> ())
105  .AddAttribute ("Library",
106  "Set the linux library to be used to create the stack",
108  StringValue ("liblinux2.6.26.so"),
109  MakeStringAccessor (&NscTcpL4Protocol::GetNscLibrary,&NscTcpL4Protocol::SetNscLibrary),
110  MakeStringChecker ())
111  ;
112  return tid;
113 }
114 
115 int external_rand ()
116 {
117  return 1; // TODO
118 }
119 
121  : m_endPoints (new Ipv4EndPointDemux ()),
122  m_nscStack (0),
123  m_nscInterface (new NscInterfaceImpl (this)),
124  m_softTimer (Timer::CANCEL_ON_DESTROY)
125 {
126  m_dlopenHandle = NULL;
127  NS_LOG_LOGIC ("Made a NscTcpL4Protocol "<<this);
128 }
129 
130 NscTcpL4Protocol::~NscTcpL4Protocol ()
131 {
132  NS_LOG_FUNCTION (this);
133  dlclose (m_dlopenHandle);
134 }
135 
136 void
137 NscTcpL4Protocol::SetNscLibrary (const std::string &soname)
138 {
139  if (soname!="")
140  {
141  m_nscLibrary = soname;
142  NS_ASSERT (!m_dlopenHandle);
143  m_dlopenHandle = dlopen (soname.c_str (), RTLD_NOW);
144  if (m_dlopenHandle == NULL)
145  NS_FATAL_ERROR (dlerror ());
146  }
147 }
148 
149 std::string
150 NscTcpL4Protocol::GetNscLibrary () const
151 {
152  return m_nscLibrary;
153 }
154 void
155 NscTcpL4Protocol::SetNode (Ptr<Node> node)
156 {
157  m_node = node;
158 
159  if (m_nscStack)
160  { // stack has already been loaded...
161  return;
162  }
163 
164  NS_ASSERT (m_dlopenHandle);
165 
166  FCreateStack create = (FCreateStack)dlsym (m_dlopenHandle, "nsc_create_stack");
167  NS_ASSERT (create);
168  m_nscStack = create (m_nscInterface, m_nscInterface, external_rand);
169  int hzval = m_nscStack->get_hz ();
170 
171  NS_ASSERT (hzval > 0);
172 
173  m_softTimer.SetFunction (&NscTcpL4Protocol::SoftInterrupt, this);
174  m_softTimer.SetDelay (MilliSeconds (1000/hzval));
175  m_nscStack->init (hzval);
176  // This enables stack and NSC debug messages
177  // m_nscStack->set_diagnostic(1000);
178 
179  Ptr<Ns3NscStack> nscStack = Create<Ns3NscStack> ();
180  nscStack->SetStack (m_nscStack);
181  node->AggregateObject (nscStack);
182 
183  m_softTimer.Schedule ();
184 
185  // its likely no ns-3 interface exits at this point, so
186  // we dealy adding the nsc interface until the start of the simulation.
187  Simulator::ScheduleNow (&NscTcpL4Protocol::AddInterface, this);
188 }
189 
190 void
192 {
193  if (m_node == 0)
194  {
195  Ptr<Node>node = this->GetObject<Node> ();
196  if (node != 0)
197  {
198  Ptr<Ipv4L3Protocol> ipv4 = this->GetObject<Ipv4L3Protocol> ();
199  if (ipv4 != 0 && m_downTarget.IsNull ())
200  {
201  this->SetNode (node);
202  ipv4->Insert (this);
203  Ptr<NscTcpSocketFactoryImpl> tcpFactory = CreateObject<NscTcpSocketFactoryImpl> ();
204  tcpFactory->SetTcp (this);
205  node->AggregateObject (tcpFactory);
207  }
208  }
209  }
211 }
212 
213 int
215 {
216  return PROT_NUMBER;
217 }
218 int
219 NscTcpL4Protocol::GetVersion (void) const
220 {
221  return 2;
222 }
223 
224 void
226 {
227  NS_LOG_FUNCTION (this);
228 
229  for (std::vector<Ptr<NscTcpSocketImpl> >::iterator i = m_sockets.begin (); i != m_sockets.end (); i++)
230  {
231  *i = 0;
232  }
233  m_sockets.clear ();
234 
235 
236  if (m_endPoints != 0)
237  {
238  delete m_endPoints;
239  m_endPoints = 0;
240  }
241  m_node = 0;
242  delete m_nscInterface;
243  m_nscInterface = 0;
244  m_downTarget.Nullify ();
246 }
247 
250 {
251  NS_LOG_FUNCTION (this);
252 
253  Ptr<NscTcpSocketImpl> socket = CreateObject<NscTcpSocketImpl> ();
254  socket->SetNode (m_node);
255  socket->SetTcp (this);
256  m_sockets.push_back (socket);
257  return socket;
258 }
259 
260 Ipv4EndPoint *
261 NscTcpL4Protocol::Allocate (void)
262 {
263  NS_LOG_FUNCTION (this);
264  return m_endPoints->Allocate ();
265 }
266 
267 Ipv4EndPoint *
268 NscTcpL4Protocol::Allocate (Ipv4Address address)
269 {
270  NS_LOG_FUNCTION (this << address);
271  return m_endPoints->Allocate (address);
272 }
273 
274 Ipv4EndPoint *
275 NscTcpL4Protocol::Allocate (uint16_t port)
276 {
277  NS_LOG_FUNCTION (this << port);
278  return m_endPoints->Allocate (port);
279 }
280 
281 Ipv4EndPoint *
282 NscTcpL4Protocol::Allocate (Ipv4Address address, uint16_t port)
283 {
284  NS_LOG_FUNCTION (this << address << port);
285  return m_endPoints->Allocate (address, port);
286 }
287 
288 Ipv4EndPoint *
289 NscTcpL4Protocol::Allocate (Ipv4Address localAddress, uint16_t localPort,
290  Ipv4Address peerAddress, uint16_t peerPort)
291 {
292  NS_LOG_FUNCTION (this << localAddress << localPort << peerAddress << peerPort);
293  return m_endPoints->Allocate (localAddress, localPort,
294  peerAddress, peerPort);
295 }
296 
297 void
298 NscTcpL4Protocol::DeAllocate (Ipv4EndPoint *endPoint)
299 {
300  NS_LOG_FUNCTION (this << endPoint);
301  // NSC m_endPoints->DeAllocate (endPoint);
302 }
303 
304 IpL4Protocol::RxStatus
306  Ipv4Header const &header,
307  Ptr<Ipv4Interface> incomingInterface)
308 {
309  NS_LOG_FUNCTION (this << packet << header << incomingInterface);
310  Ipv4Header ipHeader;
311  uint32_t packetSize = packet->GetSize ();
312 
313  // The way things work at the moment, the IP header has been removed
314  // by the ns-3 IPv4 processing code. However, the NSC stack expects
315  // a complete IP packet, so we add the IP header back.
316  // Since the original header is already gone, we create a new one
317  // based on the information we have.
318  ipHeader.SetSource (header.GetSource ());
319  ipHeader.SetDestination (header.GetDestination ());
320  ipHeader.SetProtocol (PROT_NUMBER);
321  ipHeader.SetPayloadSize (packetSize);
322  ipHeader.SetTtl (1);
323  // all NSC stacks check the IP checksum
324  ipHeader.EnableChecksum ();
325 
326  packet->AddHeader (ipHeader);
327  packetSize = packet->GetSize ();
328 
329  uint8_t *buf = new uint8_t[packetSize];
330  packet->CopyData (buf, packetSize);
331  const uint8_t *data = const_cast<uint8_t *>(buf);
332 
333  // deliver complete packet to the NSC network stack
334  m_nscStack->if_receive_packet (0, data, packetSize);
335  delete[] buf;
336 
337  wakeup ();
338  return IpL4Protocol::RX_OK;
339 }
340 
341 IpL4Protocol::RxStatus
343 {
344  return IpL4Protocol::RX_ENDPOINT_UNREACH;
345 }
346 
347 void NscTcpL4Protocol::SoftInterrupt (void)
348 {
349  m_nscStack->timer_interrupt ();
350  m_nscStack->increment_ticks ();
351  m_softTimer.Schedule ();
352 }
353 
354 void NscTcpL4Protocol::send_callback (const void* data, int datalen)
355 {
356  Ptr<Packet> p;
357  uint32_t ipv4Saddr, ipv4Daddr;
358 
359  NS_ASSERT (datalen > 20);
360 
361 
362  // create packet, without IP header. The TCP header is not touched.
363  // Not using the IP header makes integration easier, but it destroys
364  // eg. ECN.
365  const uint8_t *rawdata = reinterpret_cast<const uint8_t *>(data);
366  rawdata += 20; // skip IP header. IP options aren't supported at this time.
367  datalen -= 20;
368  p = Create<Packet> (rawdata, datalen);
369 
370  // we need the real source/destination ipv4 addresses for Send ().
371  const uint32_t *ipheader = reinterpret_cast<const uint32_t *>(data);
372  ipv4Saddr = *(ipheader+3);
373  ipv4Daddr = *(ipheader+4);
374 
375  Ipv4Address saddr (ntohl (ipv4Saddr));
376  Ipv4Address daddr (ntohl (ipv4Daddr));
377 
378  Ptr<Ipv4L3Protocol> ipv4 = m_node->GetObject<Ipv4L3Protocol> ();
379  NS_ASSERT_MSG (ipv4, "nsc callback invoked, but node has no ipv4 object");
380 
381  m_downTarget (p, saddr, daddr, PROT_NUMBER, 0);
382  m_nscStack->if_send_finish (0);
383 }
384 
385 void NscTcpL4Protocol::wakeup ()
386 {
387  // TODO
388  // this should schedule a timer to read from all tcp sockets now... this is
389  // an indication that data might be waiting on the socket
390 
391  Ipv4EndPointDemux::EndPoints endPoints = m_endPoints->GetAllEndPoints ();
392  for (Ipv4EndPointDemux::EndPointsI endPoint = endPoints.begin ();
393  endPoint != endPoints.end (); endPoint++) {
394  // NSC HACK: (ab)use TcpSocket::ForwardUp for signalling
395  (*endPoint)->ForwardUp (NULL, Ipv4Header (), 0, 0);
396  }
397 }
398 
399 void NscTcpL4Protocol::gettime (unsigned int* sec, unsigned int* usec)
400 {
401  // Only used by the Linux network stack, e.g. during ISN generation
402  // and in the kernel rng initialization routine. Also used in Linux
403  // printk output.
404  Time t = Simulator::Now ();
405  int64_t us = t.GetMicroSeconds ();
406  *sec = us / (1000*1000);
407  *usec = us - *sec * (1000*1000);
408 }
409 
410 
411 void NscTcpL4Protocol::AddInterface (void)
412 {
413  Ptr<Ipv4> ip = m_node->GetObject<Ipv4> ();
414  const uint32_t nInterfaces = ip->GetNInterfaces ();
415 
416  NS_ASSERT_MSG (nInterfaces <= 2, "nsc does not support multiple interfaces per node");
417 
418  // start from 1, ignore the loopback interface (HACK)
419  // we really don't need the loop, but its here to illustrate
420  // how things _should_ be (once nsc can deal with multiple interfaces...)
421  for (uint32_t i = 1; i < nInterfaces; i++)
422  {
423  Ipv4InterfaceAddress ifAddr = ip->GetAddress (i, 0);
424  Ipv4Address addr = ifAddr.GetLocal ();
425  Ipv4Mask mask = ifAddr.GetMask ();
426  uint16_t mtu = ip->GetMtu (i);
427 
428  std::ostringstream addrOss, maskOss;
429 
430  addr.Print (addrOss);
431  mask.Print (maskOss);
432 
433  NS_LOG_LOGIC ("if_attach " << addrOss.str ().c_str () << " " << maskOss.str ().c_str () << " " << mtu);
434 
435  std::string addrStr = addrOss.str ();
436  std::string maskStr = maskOss.str ();
437  const char* addrCStr = addrStr.c_str ();
438  const char* maskCStr = maskStr.c_str ();
439  m_nscStack->if_attach (addrCStr, maskCStr, mtu);
440 
441  if (i == 1)
442  {
443  // The NSC stack requires a default gateway and only supports
444  // single-interface nodes. The below is a hack, but
445  // it turns out that we can pass the interface address to nsc as
446  // a default gateway. Bug 1398 has been opened to track this
447  // issue (NSC's limitation to single-interface nodes)
448  //
449  // Previous versions of this code tried to assign the "next"
450  // IP address of the subnet but this was found to fail for
451  // some use cases in /30 subnets.
452 
453  // XXX
454  m_nscStack->add_default_gateway (addrOss.str ().c_str ());
455  }
456  }
457 }
458 
459 void
461 {
462  m_downTarget = callback;
463 }
464 
465 void
466 NscTcpL4Protocol::SetDownTarget6 (IpL4Protocol::DownTargetCallback6 callback)
467 {
468 }
469 
470 IpL4Protocol::DownTargetCallback
472 {
473  return m_downTarget;
474 }
475 
477 NscTcpL4Protocol::GetDownTarget6 (void) const
478 {
480 }
481 
482 } // namespace ns3
483 
void SetSource(Ipv4Address source)
Definition: ipv4-header.cc:284
void SetPayloadSize(uint16_t size)
Definition: ipv4-header.cc:56
Packet header for IPv6.
Definition: ipv6-header.h:33
void SetDestination(Ipv4Address destination)
Definition: ipv4-header.cc:297
smart pointer class similar to boost::intrusive_ptr
Definition: ptr.h:59
#define NS_LOG_FUNCTION(parameters)
Definition: log.h:311
a simple Timer class
Definition: timer.h:45
Ipv4Address GetDestination(void) const
Definition: ipv4-header.cc:303
#define NS_ASSERT(condition)
Definition: assert.h:64
#define NS_LOG_COMPONENT_DEFINE(name)
Definition: log.h:122
Ptr< Socket > CreateSocket(void)
uint32_t GetSize(void) const
Definition: packet.h:620
virtual void DoDispose(void)
Definition: object.cc:335
Ipv4Address GetSource(void) const
Definition: ipv4-header.cc:290
void SetProtocol(uint8_t num)
Definition: ipv4-header.cc:277
#define NS_FATAL_ERROR(msg)
fatal error handling
Definition: fatal-error.h:72
Demultiplexes packets to various transport layer endpoints.
Packet header for IPv4.
Definition: ipv4-header.h:31
virtual int get_hz()=0
void Schedule(void)
Definition: timer.cc:152
void SetFunction(FN fn)
Definition: timer.h:254
void EnableChecksum(void)
Enable checksum calculation for this header.
Definition: ipv4-header.cc:49
virtual void NotifyNewAggregate()
virtual void DoDispose(void)
void Send(Ptr< Packet > packet, Ipv4Address source, Ipv4Address destination, uint8_t protocol, Ptr< Ipv4Route > route)
Callback< R > MakeCallback(R(T::*memPtr)(void), OBJ objPtr)
Definition: callback.h:502
void AggregateObject(Ptr< Object > other)
Definition: object.cc:242
void SetDelay(const Time &delay)
Definition: timer.cc:69
#define NS_LOG_LOGIC(msg)
Definition: log.h:334
virtual void NotifyNewAggregate(void)
Definition: object.cc:314
virtual void SetDownTarget(IpL4Protocol::DownTargetCallback cb)
static EventId ScheduleNow(MEM mem_ptr, OBJ obj)
Definition: simulator.h:981
virtual IpL4Protocol::RxStatus Receive(Ptr< Packet > p, Ipv4Header const &header, Ptr< Ipv4Interface > incomingInterface)
Receive a packet up the protocol stack.
static Time Now(void)
Definition: simulator.cc:179
#define NS_ASSERT_MSG(condition, message)
Definition: assert.h:86
virtual int GetProtocolNumber(void) const
void SetTtl(uint8_t ttl)
Definition: ipv4-header.cc:258
uint32_t CopyData(uint8_t *buffer, uint32_t size) const
Definition: packet.cc:398
Time MilliSeconds(uint64_t ms)
create ns3::Time instances in units of milliseconds.
Definition: nstime.h:601
Ptr< T > GetObject(void) const
Definition: object.h:332
void AddHeader(const Header &header)
Definition: packet.cc:270
A representation of an internet endpoint/connection.
virtual IpL4Protocol::DownTargetCallback GetDownTarget(void) const