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 
55 /* see http://www.iana.org/assignments/protocol-numbers */
56 const uint8_t NscTcpL4Protocol::PROT_NUMBER = 6;
57 
63 {
64 public:
70 private:
80  virtual void send_callback (const void *data, int datalen);
87  virtual void wakeup ();
94  virtual void gettime (unsigned int *, unsigned int *);
95 private:
97 };
98 
100  : m_prot (prot)
101 {
102 }
103 
104 void
105 NscInterfaceImpl::send_callback (const void *data, int datalen)
106 {
107  m_prot->send_callback (data, datalen);
108 }
109 void
111 {
112  m_prot->wakeup ();
113 }
114 void
115 NscInterfaceImpl::gettime (unsigned int *sec, unsigned int *usec)
116 {
117  m_prot->gettime (sec,usec);
118 }
119 
120 
121 #undef NS_LOG_APPEND_CONTEXT
122 #define NS_LOG_APPEND_CONTEXT \
123  if (m_node) { std::clog << Simulator::Now ().GetSeconds () << " [node " << m_node->GetId () << "] "; }
124 
125 TypeId
127 {
128  static TypeId tid = TypeId ("ns3::NscTcpL4Protocol")
130  .AddConstructor<NscTcpL4Protocol>()
131  .AddAttribute ("SocketList", "The list of sockets associated to this protocol.",
134  MakeObjectVectorChecker<NscTcpSocketImpl> ())
135  .AddAttribute ("Library",
136  "Set the linux library to be used to create the stack",
138  StringValue ("liblinux2.6.26.so"),
140  MakeStringChecker ())
141  ;
142  return tid;
143 }
144 
153 {
154  return 1;
155 }
156 
158  : m_endPoints (new Ipv4EndPointDemux ()),
159  m_nscStack (0),
160  m_nscInterface (new NscInterfaceImpl (this)),
161  m_softTimer (Timer::CANCEL_ON_DESTROY)
162 {
163  m_dlopenHandle = NULL;
164  NS_LOG_LOGIC ("Made a NscTcpL4Protocol "<<this);
165 }
166 
168 {
169  NS_LOG_FUNCTION (this);
170  dlclose (m_dlopenHandle);
171 }
172 
173 void
174 NscTcpL4Protocol::SetNscLibrary (const std::string &soname)
175 {
176  if (soname!="")
177  {
178  m_nscLibrary = soname;
180  m_dlopenHandle = dlopen (soname.c_str (), RTLD_NOW);
181  if (m_dlopenHandle == NULL)
182  NS_FATAL_ERROR (dlerror ());
183  }
184 }
185 
186 std::string
188 {
189  return m_nscLibrary;
190 }
191 void
193 {
194  m_node = node;
195 
196  if (m_nscStack)
197  { // stack has already been loaded...
198  return;
199  }
200 
202 
203  FCreateStack create = (FCreateStack)dlsym (m_dlopenHandle, "nsc_create_stack");
204  NS_ASSERT (create);
206  int hzval = m_nscStack->get_hz ();
207 
208  NS_ASSERT (hzval > 0);
209 
211  m_softTimer.SetDelay (MilliSeconds (1000/hzval));
212  m_nscStack->init (hzval);
213  // This enables stack and NSC debug messages
214  // m_nscStack->set_diagnostic(1000);
215 
216  Ptr<Ns3NscStack> nscStack = Create<Ns3NscStack> ();
217  nscStack->SetStack (m_nscStack);
218  node->AggregateObject (nscStack);
219 
221 
222  // its likely no ns-3 interface exits at this point, so
223  // we dealy adding the nsc interface until the start of the simulation.
225 }
226 
227 void
229 {
230  if (m_node == 0)
231  {
232  Ptr<Node>node = this->GetObject<Node> ();
233  if (node != 0)
234  {
235  Ptr<Ipv4L3Protocol> ipv4 = this->GetObject<Ipv4L3Protocol> ();
236  if (ipv4 != 0 && m_downTarget.IsNull ())
237  {
238  this->SetNode (node);
239  ipv4->Insert (this);
240  Ptr<NscTcpSocketFactoryImpl> tcpFactory = CreateObject<NscTcpSocketFactoryImpl> ();
241  tcpFactory->SetTcp (this);
242  node->AggregateObject (tcpFactory);
244  }
245  }
246  }
248 }
249 
250 int
252 {
253  return PROT_NUMBER;
254 }
255 int
257 {
258  return 2;
259 }
260 
261 void
263 {
264  NS_LOG_FUNCTION (this);
265 
266  for (std::vector<Ptr<NscTcpSocketImpl> >::iterator i = m_sockets.begin (); i != m_sockets.end (); i++)
267  {
268  *i = 0;
269  }
270  m_sockets.clear ();
271 
272 
273  if (m_endPoints != 0)
274  {
275  delete m_endPoints;
276  m_endPoints = 0;
277  }
278  m_node = 0;
279  delete m_nscInterface;
280  m_nscInterface = 0;
283 }
284 
287 {
288  NS_LOG_FUNCTION (this);
289 
290  Ptr<NscTcpSocketImpl> socket = CreateObject<NscTcpSocketImpl> ();
291  socket->SetNode (m_node);
292  socket->SetTcp (this);
293  m_sockets.push_back (socket);
294  return socket;
295 }
296 
297 Ipv4EndPoint *
299 {
300  NS_LOG_FUNCTION (this);
301  return m_endPoints->Allocate ();
302 }
303 
304 Ipv4EndPoint *
306 {
307  NS_LOG_FUNCTION (this << address);
308  return m_endPoints->Allocate (address);
309 }
310 
311 Ipv4EndPoint *
313 {
314  NS_LOG_FUNCTION (this << port);
315  return m_endPoints->Allocate (port);
316 }
317 
318 Ipv4EndPoint *
320 {
321  NS_LOG_FUNCTION (this << address << port);
322  return m_endPoints->Allocate (address, port);
323 }
324 
325 Ipv4EndPoint *
326 NscTcpL4Protocol::Allocate (Ipv4Address localAddress, uint16_t localPort,
327  Ipv4Address peerAddress, uint16_t peerPort)
328 {
329  NS_LOG_FUNCTION (this << localAddress << localPort << peerAddress << peerPort);
330  return m_endPoints->Allocate (localAddress, localPort,
331  peerAddress, peerPort);
332 }
333 
334 void
336 {
337  NS_LOG_FUNCTION (this << endPoint);
338  // NSC m_endPoints->DeAllocate (endPoint);
339 }
340 
343  Ipv4Header const &header,
344  Ptr<Ipv4Interface> incomingInterface)
345 {
346  NS_LOG_FUNCTION (this << packet << header << incomingInterface);
347  Ipv4Header ipHeader;
348  uint32_t packetSize = packet->GetSize ();
349 
350  // The way things work at the moment, the IP header has been removed
351  // by the ns-3 IPv4 processing code. However, the NSC stack expects
352  // a complete IP packet, so we add the IP header back.
353  // Since the original header is already gone, we create a new one
354  // based on the information we have.
355  ipHeader.SetSource (header.GetSource ());
356  ipHeader.SetDestination (header.GetDestination ());
357  ipHeader.SetProtocol (PROT_NUMBER);
358  ipHeader.SetPayloadSize (packetSize);
359  ipHeader.SetTtl (1);
360  // all NSC stacks check the IP checksum
361  ipHeader.EnableChecksum ();
362 
363  packet->AddHeader (ipHeader);
364  packetSize = packet->GetSize ();
365 
366  uint8_t *buf = new uint8_t[packetSize];
367  packet->CopyData (buf, packetSize);
368  const uint8_t *data = const_cast<uint8_t *>(buf);
369 
370  // deliver complete packet to the NSC network stack
371  m_nscStack->if_receive_packet (0, data, packetSize);
372  delete[] buf;
373 
374  wakeup ();
375  return IpL4Protocol::RX_OK;
376 }
377 
380 {
382 }
383 
385 {
389 }
390 
391 void NscTcpL4Protocol::send_callback (const void* data, int datalen)
392 {
393  Ptr<Packet> p;
394  uint32_t ipv4Saddr, ipv4Daddr;
395 
396  NS_ASSERT (datalen > 20);
397 
398 
399  // create packet, without IP header. The TCP header is not touched.
400  // Not using the IP header makes integration easier, but it destroys
401  // eg. ECN.
402  const uint8_t *rawdata = reinterpret_cast<const uint8_t *>(data);
403  rawdata += 20; // skip IP header. IP options aren't supported at this time.
404  datalen -= 20;
405  p = Create<Packet> (rawdata, datalen);
406 
407  // we need the real source/destination ipv4 addresses for Send ().
408  const uint32_t *ipheader = reinterpret_cast<const uint32_t *>(data);
409  ipv4Saddr = *(ipheader+3);
410  ipv4Daddr = *(ipheader+4);
411 
412  Ipv4Address saddr (ntohl (ipv4Saddr));
413  Ipv4Address daddr (ntohl (ipv4Daddr));
414 
416  NS_ASSERT_MSG (ipv4, "nsc callback invoked, but node has no ipv4 object");
417 
418  m_downTarget (p, saddr, daddr, PROT_NUMBER, 0);
420 }
421 
423 {
424  // \todo
425  // this should schedule a timer to read from all tcp sockets now... this is
426  // an indication that data might be waiting on the socket
427 
429  for (Ipv4EndPointDemux::EndPointsI endPoint = endPoints.begin ();
430  endPoint != endPoints.end (); endPoint++) {
431  // NSC HACK: (ab)use TcpSocket::ForwardUp for signalling
432  (*endPoint)->ForwardUp (NULL, Ipv4Header (), 0, 0);
433  }
434 }
435 
436 void NscTcpL4Protocol::gettime (unsigned int* sec, unsigned int* usec)
437 {
438  // Only used by the Linux network stack, e.g. during ISN generation
439  // and in the kernel rng initialization routine. Also used in Linux
440  // printk output.
441  Time t = Simulator::Now ();
442  int64_t us = t.GetMicroSeconds ();
443  *sec = us / (1000*1000);
444  *usec = us - *sec * (1000*1000);
445 }
446 
447 
449 {
450  Ptr<Ipv4> ip = m_node->GetObject<Ipv4> ();
451  const uint32_t nInterfaces = ip->GetNInterfaces ();
452 
453  NS_ASSERT_MSG (nInterfaces <= 2, "nsc does not support multiple interfaces per node");
454 
455  // start from 1, ignore the loopback interface (HACK)
456  // we really don't need the loop, but its here to illustrate
457  // how things _should_ be (once nsc can deal with multiple interfaces...)
458  for (uint32_t i = 1; i < nInterfaces; i++)
459  {
460  Ipv4InterfaceAddress ifAddr = ip->GetAddress (i, 0);
461  Ipv4Address addr = ifAddr.GetLocal ();
462  Ipv4Mask mask = ifAddr.GetMask ();
463  uint16_t mtu = ip->GetMtu (i);
464 
465  std::ostringstream addrOss, maskOss;
466 
467  addr.Print (addrOss);
468  mask.Print (maskOss);
469 
470  NS_LOG_LOGIC ("if_attach " << addrOss.str ().c_str () << " " << maskOss.str ().c_str () << " " << mtu);
471 
472  std::string addrStr = addrOss.str ();
473  std::string maskStr = maskOss.str ();
474  const char* addrCStr = addrStr.c_str ();
475  const char* maskCStr = maskStr.c_str ();
476  m_nscStack->if_attach (addrCStr, maskCStr, mtu);
477 
478  if (i == 1)
479  {
480  // The NSC stack requires a default gateway and only supports
481  // single-interface nodes. The below is a hack, but
482  // it turns out that we can pass the interface address to nsc as
483  // a default gateway. Bug 1398 has been opened to track this
484  // issue (NSC's limitation to single-interface nodes)
485  //
486  // Previous versions of this code tried to assign the "next"
487  // IP address of the subnet but this was found to fail for
488  // some use cases in /30 subnets.
489 
490  // \todo \bugid{1398} NSC's limitation to single-interface nodes
491  m_nscStack->add_default_gateway (addrOss.str ().c_str ());
492  }
493  }
494 }
495 
496 void
498 {
499  m_downTarget = callback;
500 }
501 
502 void
504 {
505 }
506 
509 {
510  return m_downTarget;
511 }
512 
515 {
517 }
518 
519 } // namespace ns3
520 
void SetSource(Ipv4Address source)
Definition: ipv4-header.cc:285
void SetPayloadSize(uint16_t size)
Definition: ipv4-header.cc:57
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.
keep track of time values and allow control of global simulation resolution
Definition: nstime.h:81
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:59
#define NS_LOG_FUNCTION(parameters)
Definition: log.h:345
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
Ipv4Address GetLocal(void) const
Get the local address.
hold variables of type string
Definition: string.h:19
a class to represent an Ipv4 address mask
Definition: ipv4-address.h:210
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:1014
std::string m_nscLibrary
path to the NSC library.
#define NS_ASSERT(condition)
Definition: assert.h:64
NS_OBJECT_ENSURE_REGISTERED(NullMessageSimulatorImpl)
EndPoints GetAllEndPoints(void)
Get the entire list of end points registered.
Ptr< Socket > CreateSocket(void)
int external_rand()
External Random number generator.
uint32_t GetSize(void) const
Definition: packet.h:650
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:336
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.
#define NS_FATAL_ERROR(msg)
fatal error handling
Definition: fatal-error.h:72
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:291
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
NS_LOG_COMPONENT_DEFINE("NscTcpL4Protocol")
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:50
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:1238
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:243
void SetDelay(const Time &delay)
Definition: timer.cc:69
#define NS_LOG_LOGIC(msg)
Definition: log.h:368
virtual void NotifyNewAggregate(void)
This method is invoked whenever two sets of objects are aggregated together.
Definition: object.cc:315
Access to the Ipv4 forwarding table, interfaces, and configuration.
Definition: ipv4.h:75
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:985
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)
Definition: assert.h:86
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:1018
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:361
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:611
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.