A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
nsc-tcp-l4-protocol.cc
Go to the documentation of this file.
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"
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 
62 {
63 public:
69 private:
79  virtual void send_callback (const void *data, int datalen);
86  virtual void wakeup ();
93  virtual void gettime (unsigned int *, unsigned int *);
94 private:
96 };
97 
99  : m_prot (prot)
100 {
101 }
102 
103 void
104 NscInterfaceImpl::send_callback (const void *data, int datalen)
105 {
106  m_prot->send_callback (data, datalen);
107 }
108 void
110 {
111  m_prot->wakeup ();
112 }
113 void
114 NscInterfaceImpl::gettime (unsigned int *sec, unsigned int *usec)
115 {
116  m_prot->gettime (sec,usec);
117 }
118 
119 
120 #undef NS_LOG_APPEND_CONTEXT
121 #define NS_LOG_APPEND_CONTEXT \
122  if (m_node) { std::clog << Simulator::Now ().GetSeconds () << " [node " << m_node->GetId () << "] "; }
123 
124 TypeId
126 {
127  static TypeId tid = TypeId ("ns3::NscTcpL4Protocol")
129  .AddConstructor<NscTcpL4Protocol>()
130  .AddAttribute ("SocketList", "The list of sockets associated to this protocol.",
133  MakeObjectVectorChecker<NscTcpSocketImpl> ())
134  .AddAttribute ("Library",
135  "Set the linux library to be used to create the stack",
137  StringValue ("liblinux2.6.26.so"),
139  MakeStringChecker ())
140  ;
141  return tid;
142 }
143 
152 {
153  return 1;
154 }
155 
157  : m_endPoints (new Ipv4EndPointDemux ()),
158  m_nscStack (0),
159  m_nscInterface (new NscInterfaceImpl (this)),
160  m_softTimer (Timer::CANCEL_ON_DESTROY)
161 {
162  m_dlopenHandle = NULL;
163  NS_LOG_LOGIC ("Made a NscTcpL4Protocol "<<this);
164 }
165 
167 {
168  NS_LOG_FUNCTION (this);
169  dlclose (m_dlopenHandle);
170 }
171 
172 void
173 NscTcpL4Protocol::SetNscLibrary (const std::string &soname)
174 {
175  if (soname!="")
176  {
177  m_nscLibrary = soname;
179  m_dlopenHandle = dlopen (soname.c_str (), RTLD_NOW);
180  if (m_dlopenHandle == NULL)
181  NS_FATAL_ERROR (dlerror ());
182  }
183 }
184 
185 std::string
187 {
188  return m_nscLibrary;
189 }
190 void
192 {
193  m_node = node;
194 
195  if (m_nscStack)
196  { // stack has already been loaded...
197  return;
198  }
199 
201 
202  FCreateStack create = (FCreateStack)dlsym (m_dlopenHandle, "nsc_create_stack");
203  NS_ASSERT (create);
205  int hzval = m_nscStack->get_hz ();
206 
207  NS_ASSERT (hzval > 0);
208 
210  m_softTimer.SetDelay (MilliSeconds (1000/hzval));
211  m_nscStack->init (hzval);
212  // This enables stack and NSC debug messages
213  // m_nscStack->set_diagnostic(1000);
214 
215  Ptr<Ns3NscStack> nscStack = Create<Ns3NscStack> ();
216  nscStack->SetStack (m_nscStack);
217  node->AggregateObject (nscStack);
218 
220 
221  // its likely no ns-3 interface exits at this point, so
222  // we dealy adding the nsc interface until the start of the simulation.
224 }
225 
226 void
228 {
229  if (m_node == 0)
230  {
231  Ptr<Node>node = this->GetObject<Node> ();
232  if (node != 0)
233  {
234  Ptr<Ipv4L3Protocol> ipv4 = this->GetObject<Ipv4L3Protocol> ();
235  if (ipv4 != 0 && m_downTarget.IsNull ())
236  {
237  this->SetNode (node);
238  ipv4->Insert (this);
239  Ptr<NscTcpSocketFactoryImpl> tcpFactory = CreateObject<NscTcpSocketFactoryImpl> ();
240  tcpFactory->SetTcp (this);
241  node->AggregateObject (tcpFactory);
243  }
244  }
245  }
247 }
248 
249 int
251 {
252  return PROT_NUMBER;
253 }
254 int
256 {
257  return 2;
258 }
259 
260 void
262 {
263  NS_LOG_FUNCTION (this);
264 
265  for (std::vector<Ptr<NscTcpSocketImpl> >::iterator i = m_sockets.begin (); i != m_sockets.end (); i++)
266  {
267  *i = 0;
268  }
269  m_sockets.clear ();
270 
271 
272  if (m_endPoints != 0)
273  {
274  delete m_endPoints;
275  m_endPoints = 0;
276  }
277  m_node = 0;
278  delete m_nscInterface;
279  m_nscInterface = 0;
282 }
283 
286 {
287  NS_LOG_FUNCTION (this);
288 
289  Ptr<NscTcpSocketImpl> socket = CreateObject<NscTcpSocketImpl> ();
290  socket->SetNode (m_node);
291  socket->SetTcp (this);
292  m_sockets.push_back (socket);
293  return socket;
294 }
295 
296 Ipv4EndPoint *
298 {
299  NS_LOG_FUNCTION (this);
300  return m_endPoints->Allocate ();
301 }
302 
303 Ipv4EndPoint *
305 {
306  NS_LOG_FUNCTION (this << address);
307  return m_endPoints->Allocate (address);
308 }
309 
310 Ipv4EndPoint *
312 {
313  NS_LOG_FUNCTION (this << port);
314  return m_endPoints->Allocate (port);
315 }
316 
317 Ipv4EndPoint *
319 {
320  NS_LOG_FUNCTION (this << address << port);
321  return m_endPoints->Allocate (address, port);
322 }
323 
324 Ipv4EndPoint *
325 NscTcpL4Protocol::Allocate (Ipv4Address localAddress, uint16_t localPort,
326  Ipv4Address peerAddress, uint16_t peerPort)
327 {
328  NS_LOG_FUNCTION (this << localAddress << localPort << peerAddress << peerPort);
329  return m_endPoints->Allocate (localAddress, localPort,
330  peerAddress, peerPort);
331 }
332 
333 void
335 {
336  NS_LOG_FUNCTION (this << endPoint);
337  // NSC m_endPoints->DeAllocate (endPoint);
338 }
339 
342  Ipv4Header const &header,
343  Ptr<Ipv4Interface> incomingInterface)
344 {
345  NS_LOG_FUNCTION (this << packet << header << incomingInterface);
346  Ipv4Header ipHeader;
347  uint32_t packetSize = packet->GetSize ();
348 
349  // The way things work at the moment, the IP header has been removed
350  // by the ns-3 IPv4 processing code. However, the NSC stack expects
351  // a complete IP packet, so we add the IP header back.
352  // Since the original header is already gone, we create a new one
353  // based on the information we have.
354  ipHeader.SetSource (header.GetSource ());
355  ipHeader.SetDestination (header.GetDestination ());
356  ipHeader.SetProtocol (PROT_NUMBER);
357  ipHeader.SetPayloadSize (packetSize);
358  ipHeader.SetTtl (1);
359  // all NSC stacks check the IP checksum
360  ipHeader.EnableChecksum ();
361 
362  packet->AddHeader (ipHeader);
363  packetSize = packet->GetSize ();
364 
365  uint8_t *buf = new uint8_t[packetSize];
366  packet->CopyData (buf, packetSize);
367  const uint8_t *data = const_cast<uint8_t *>(buf);
368 
369  // deliver complete packet to the NSC network stack
370  m_nscStack->if_receive_packet (0, data, packetSize);
371  delete[] buf;
372 
373  wakeup ();
374  return IpL4Protocol::RX_OK;
375 }
376 
379 {
381 }
382 
384 {
388 }
389 
390 void NscTcpL4Protocol::send_callback (const void* data, int datalen)
391 {
392  Ptr<Packet> p;
393  uint32_t ipv4Saddr, ipv4Daddr;
394 
395  NS_ASSERT (datalen > 20);
396 
397 
398  // create packet, without IP header. The TCP header is not touched.
399  // Not using the IP header makes integration easier, but it destroys
400  // eg. ECN.
401  const uint8_t *rawdata = reinterpret_cast<const uint8_t *>(data);
402  rawdata += 20; // skip IP header. IP options aren't supported at this time.
403  datalen -= 20;
404  p = Create<Packet> (rawdata, datalen);
405 
406  // we need the real source/destination ipv4 addresses for Send ().
407  const uint32_t *ipheader = reinterpret_cast<const uint32_t *>(data);
408  ipv4Saddr = *(ipheader+3);
409  ipv4Daddr = *(ipheader+4);
410 
411  Ipv4Address saddr (ntohl (ipv4Saddr));
412  Ipv4Address daddr (ntohl (ipv4Daddr));
413 
415  NS_ASSERT_MSG (ipv4, "nsc callback invoked, but node has no ipv4 object");
416 
417  m_downTarget (p, saddr, daddr, PROT_NUMBER, 0);
419 }
420 
422 {
423  // \todo
424  // this should schedule a timer to read from all tcp sockets now... this is
425  // an indication that data might be waiting on the socket
426 
428  for (Ipv4EndPointDemux::EndPointsI endPoint = endPoints.begin ();
429  endPoint != endPoints.end (); endPoint++) {
430  // NSC HACK: (ab)use TcpSocket::ForwardUp for signalling
431  (*endPoint)->ForwardUp (NULL, Ipv4Header (), 0, 0);
432  }
433 }
434 
435 void NscTcpL4Protocol::gettime (unsigned int* sec, unsigned int* usec)
436 {
437  // Only used by the Linux network stack, e.g. during ISN generation
438  // and in the kernel rng initialization routine. Also used in Linux
439  // printk output.
440  Time t = Simulator::Now ();
441  int64_t us = t.GetMicroSeconds ();
442  *sec = us / (1000*1000);
443  *usec = us - *sec * (1000*1000);
444 }
445 
446 
448 {
449  Ptr<Ipv4> ip = m_node->GetObject<Ipv4> ();
450  const uint32_t nInterfaces = ip->GetNInterfaces ();
451 
452  NS_ASSERT_MSG (nInterfaces <= 2, "nsc does not support multiple interfaces per node");
453 
454  // start from 1, ignore the loopback interface (HACK)
455  // we really don't need the loop, but its here to illustrate
456  // how things _should_ be (once nsc can deal with multiple interfaces...)
457  for (uint32_t i = 1; i < nInterfaces; i++)
458  {
459  Ipv4InterfaceAddress ifAddr = ip->GetAddress (i, 0);
460  Ipv4Address addr = ifAddr.GetLocal ();
461  Ipv4Mask mask = ifAddr.GetMask ();
462  uint16_t mtu = ip->GetMtu (i);
463 
464  std::ostringstream addrOss, maskOss;
465 
466  addr.Print (addrOss);
467  mask.Print (maskOss);
468 
469  NS_LOG_LOGIC ("if_attach " << addrOss.str ().c_str () << " " << maskOss.str ().c_str () << " " << mtu);
470 
471  std::string addrStr = addrOss.str ();
472  std::string maskStr = maskOss.str ();
473  const char* addrCStr = addrStr.c_str ();
474  const char* maskCStr = maskStr.c_str ();
475  m_nscStack->if_attach (addrCStr, maskCStr, mtu);
476 
477  if (i == 1)
478  {
479  // The NSC stack requires a default gateway and only supports
480  // single-interface nodes. The below is a hack, but
481  // it turns out that we can pass the interface address to nsc as
482  // a default gateway. Bug 1398 has been opened to track this
483  // issue (NSC's limitation to single-interface nodes)
484  //
485  // Previous versions of this code tried to assign the "next"
486  // IP address of the subnet but this was found to fail for
487  // some use cases in /30 subnets.
488 
489  // \todo \bugid{1398} NSC's limitation to single-interface nodes
490  m_nscStack->add_default_gateway (addrOss.str ().c_str ());
491  }
492  }
493 }
494 
495 void
497 {
498  m_downTarget = callback;
499 }
500 
501 void
503 {
504 }
505 
508 {
509  return m_downTarget;
510 }
511 
514 {
516 }
517 
518 } // namespace ns3
519 
void SetSource(Ipv4Address source)
Definition: ipv4-header.cc:285
void SetPayloadSize(uint16_t size)
Definition: ipv4-header.cc:56
Ptr< const AttributeAccessor > MakeObjectVectorAccessor(U T::*memberContainer)
Definition: object-vector.h:51
virtual void if_receive_packet(int if_id, const void *data, int datalen)=0
Deliver complete packet to the NSC network stack.
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:79
void SoftInterrupt(void)
Provide a "soft" interrupt to NSC.
Doxygen introspection did not find any typical Config paths.
Definition: ipv6-header.h:33
void SetDestination(Ipv4Address destination)
Definition: ipv4-header.cc:298
smart pointer class similar to boost::intrusive_ptr
Definition: ptr.h:60
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by "...
Ipv4Mask GetMask(void) const
Get the network mask.
virtual void wakeup()
Called by the NSC stack whenever something of interest has happened.
a simple Timer class
Definition: timer.h:45
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register the class in the ns-3 factory.
Definition: object-base.h:38
Ipv4Address GetLocal(void) const
Get the local address.
hold variables of type string
Definition: string.h:18
a class to represent an Ipv4 address mask
Definition: ipv4-address.h:222
IpL4Protocol::DownTargetCallback m_downTarget
Callback to send packets over IPv4.
Ipv4Address GetDestination(void) const
Definition: ipv4-header.cc:304
bool IsNull(void) const
Check for null implementation.
Definition: callback.h:1018
std::string m_nscLibrary
path to the NSC library.
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file...
Definition: assert.h:61
EndPoints GetAllEndPoints(void)
Get the entire list of end points registered.
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:170
Ptr< Socket > CreateSocket(void)
int external_rand()
External Random number generator.
uint32_t GetSize(void) const
Returns the the size in bytes of the packet (including the zero-filled initial payload).
Definition: packet.h:744
static TypeId GetTypeId(void)
Get the type ID.
virtual void DoDispose(void)
This method is called by Object::Dispose or by the object's destructor, whichever comes first...
Definition: object.cc:335
#define NS_FATAL_ERROR(msg)
fatal error handling
Definition: fatal-error.h:95
Ipv4Address GetSource(void) const
Definition: ipv4-header.cc:291
The attribute can be written at construction-time.
Definition: type-id.h:58
void SetProtocol(uint8_t num)
Definition: ipv4-header.cc:278
void wakeup()
Called by the NSC stack whenever something of interest has happened.
virtual IpL4Protocol::DownTargetCallback6 GetDownTarget6(void) const
This method allows a caller to get the current down target callback set for this L4 protocol (IPv6 ca...
void SetNscLibrary(const std::string &lib)
Set the NSC library to be used.
uint16_t port
Definition: dsdv-manet.cc:44
virtual void increment_ticks()=0
Increment the time ticks.
virtual int GetVersion(void) const
Get the NSC version.
Struct interface to NSC send capabilities.
NscInterfaceImpl * m_nscInterface
the NSC Interface.
Demultiplexes packets to various transport layer endpoints.
The attribute can be read.
Definition: type-id.h:56
NscInterfaceImpl(Ptr< NscTcpL4Protocol > prot)
Constructor.
Packet header for IPv4.
Definition: ipv4-header.h:31
virtual void SetDownTarget6(IpL4Protocol::DownTargetCallback6 cb)
This method allows a caller to set the current down target callback set for this L4 protocol (IPv6 ca...
void SetNode(Ptr< Node > node)
Set node associated with this stack.
int64_t GetMicroSeconds(void) const
Definition: nstime.h:289
virtual int get_hz()=0
Get the timer_interrupt frequency.
void Schedule(void)
Schedule a new event using the currently-configured delay, function, and arguments.
Definition: timer.cc:152
void SetFunction(FN fn)
Definition: timer.h:254
uint8_t data[writeSize]
void EnableChecksum(void)
Enable checksum calculation for this header.
Definition: ipv4-header.cc:49
virtual void NotifyNewAggregate()
This method is invoked whenever two sets of objects are aggregated together.
virtual void DoDispose(void)
This method is called by Object::Dispose or by the object's destructor, whichever comes first...
Callback< R > MakeCallback(R(T::*memPtr)(void), OBJ objPtr)
Definition: callback.h:1242
void Send(Ptr< Packet > packet, Ipv4Address source, Ipv4Address destination, uint8_t protocol, Ptr< Ipv4Route > route)
void Print(std::ostream &os) const
Print this address to the given output stream.
std::string GetNscLibrary(void) const
Get the NSC library being used.
Ptr< NscTcpL4Protocol > m_prot
the NSC TCP protocol
INetStack *(* FCreateStack)(ISendCallback *, IInterruptCallback *, FRandom)
void AggregateObject(Ptr< Object > other)
Definition: object.cc:242
void SetDelay(const Time &delay)
Definition: timer.cc:69
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition: log.h:233
virtual void NotifyNewAggregate(void)
This method is invoked whenever two sets of objects are aggregated together.
Definition: object.cc:314
Access to the Ipv4 forwarding table, interfaces, and configuration.
Definition: ipv4.h:76
Struct interface to NSC soft interrupt capabilities.
virtual void SetDownTarget(IpL4Protocol::DownTargetCallback cb)
This method allows a caller to set the current down target callback set for this L4 protocol (IPv4 ca...
void AddInterface(void)
Add an interface.
virtual void timer_interrupt()=0
The stack timer_interrupt function.
Implement the Ipv4 layer.
Nsc interface implementation class.
static EventId ScheduleNow(MEM mem_ptr, OBJ obj)
Schedule an event to expire Now.
Definition: simulator.h:986
INetStack * m_nscStack
the NSC stack.
virtual IpL4Protocol::RxStatus Receive(Ptr< Packet > p, Ipv4Header const &header, Ptr< Ipv4Interface > incomingInterface)
Called from lower-level layers to send the packet up in the stack.
L4 Protocol abstract base class.
static Time Now(void)
Return the "current simulation time".
Definition: simulator.cc:180
void Print(std::ostream &os) const
Print this mask to the given output stream.
virtual void add_default_gateway(const char *addr)=0
Add a default gateway to the interface.
static const uint8_t PROT_NUMBER
protocol number (0x6)
Ptr< Node > m_node
the node this stack is associated with
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition: assert.h:84
Ipv4EndPointDemux * m_endPoints
A list of IPv4 end points.
Ipv4 addresses are stored in host order in this class.
Definition: ipv4-address.h:38
std::list< Ipv4EndPoint * > EndPoints
Container of the IPv4 endpoints.
std::vector< Ptr< NscTcpSocketImpl > > m_sockets
list of sockets
a class to store IPv4 address information on an interface
void DeAllocate(Ipv4EndPoint *endPoint)
Remove an IPv4 Endpoint.
virtual int GetProtocolNumber(void) const
void SetTtl(uint8_t ttl)
Definition: ipv4-header.cc:259
virtual void if_attach(const char *addr, const char *mask, int mtu)=0
Attach an interface to the stack.
void Nullify(void)
Discard the implementation, set it to null.
Definition: callback.h:1022
std::list< Ipv4EndPoint * >::iterator EndPointsI
Iterator to the container of the IPv4 endpoints.
uint32_t CopyData(uint8_t *buffer, uint32_t size) const
Copy the packet contents to a byte buffer.
Definition: packet.cc:381
Ipv4EndPoint * Allocate(void)
Allocate an IPv4 Endpoint.
RxStatus
Rx status codes.
virtual void if_send_finish(int if_id)=0
Signal the completion of send procedure to the NSC network stack.
virtual void init(int hz)=0
Initialize the stack.
tuple address
Definition: first.py:37
contain a set of ns3::Object pointers.
virtual void gettime(unsigned int *, unsigned int *)
Called by the Linux stack RNG initialization.
Ptr< T > GetObject(void) const
Definition: object.h:362
a unique identifier for an interface.
Definition: type-id.h:49
void * m_dlopenHandle
dynamic library handle.
TypeId SetParent(TypeId tid)
Definition: type-id.cc:610
void gettime(unsigned int *sec, unsigned int *usec)
Called by the Linux stack RNG initialization.
Timer m_softTimer
Soft interrupt timer.
void AddHeader(const Header &header)
Add header to this packet.
Definition: packet.cc:253
A representation of an internet endpoint/connection.
void send_callback(const void *data, int datalen)
Invoked by NSCs 'ethernet driver' to re-inject a packet into ns-3.
virtual IpL4Protocol::DownTargetCallback GetDownTarget(void) const
This method allows a caller to get the current down target callback set for this L4 protocol (IPv4 ca...
virtual void send_callback(const void *data, int datalen)
Invoked by NSCs 'ethernet driver' to re-inject a packet into ns-3.
Ipv4EndPoint * Allocate(void)
Allocate a Ipv4EndPoint.