A Discrete-Event Network Simulator
API
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 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 
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  .SetGroupName ("Internet")
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"),
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:56
Ptr< const AttributeChecker > MakeStringChecker(void)
Definition: string.cc:30
virtual void if_receive_packet(int if_id, const void *data, int datalen)=0
Deliver complete packet to the NSC network stack.
Nsc wrapper glue, to interface with the Ipv4 protocol underneath.
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:102
void SoftInterrupt(void)
Provide a "soft" interrupt to NSC.
Packet header for IPv6.
Definition: ipv6-header.h:34
void SetDestination(Ipv4Address destination)
Definition: ipv4-header.cc:298
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:73
#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:73
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:44
Ipv4Address GetLocal(void) const
Get the local address.
Ptr< T > GetObject(void) const
Get a pointer to the requested aggregated Object.
Definition: object.h:462
Hold variables of type string.
Definition: string.h:41
a class to represent an Ipv4 address mask
Definition: ipv4-address.h:257
void AggregateObject(Ptr< Object > other)
Aggregate two Objects together.
Definition: object.cc:252
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:1270
Ptr< const AttributeAccessor > MakeObjectVectorAccessor(U T::*memberVariable)
MakeAccessorHelper implementation for ObjectVector.
Definition: object-vector.h:81
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:67
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:201
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:903
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:792
static TypeId GetTypeId(void)
Get the type ID.
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:162
Ipv4Address GetSource(void) const
Definition: ipv4-header.cc:291
virtual void DoDispose(void)
Destructor implementation.
Definition: object.cc:346
void SetProtocol(uint8_t num)
Definition: ipv4-header.cc:278
void wakeup()
Called by the NSC stack whenever something of interest has happened.
RxStatus
Rx status codes.
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.
The attribute can be written at construction-time.
Definition: type-id.h:65
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.
NscInterfaceImpl(Ptr< NscTcpL4Protocol > prot)
Constructor.
Packet header for IPv4.
Definition: ipv4-header.h:33
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
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:349
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:158
void SetFunction(FN fn)
Definition: timer.h:309
uint8_t data[writeSize]
void EnableChecksum(void)
Enable checksum calculation for this header.
Definition: ipv4-header.cc:49
virtual void NotifyNewAggregate()
Notify all Objects aggregated to this one of a new Object being aggregated.
virtual void DoDispose(void)
Destructor implementation.
Callback< R > MakeCallback(R(T::*memPtr)(void), OBJ objPtr)
Definition: callback.h:1489
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
void SetDelay(const Time &delay)
Definition: timer.cc:75
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition: log.h:252
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.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
INetStack *(* FCreateStack)(ISendCallback *, IInterruptCallback *, FRandom)
Nsc interface implementation class.
static EventId ScheduleNow(MEM mem_ptr, OBJ obj)
Schedule an event to expire Now.
Definition: simulator.h:1401
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 virtual time.
Definition: simulator.cc:224
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:90
Ipv4EndPointDemux * m_endPoints
A list of IPv4 end points.
Ipv4 addresses are stored in host order in this class.
Definition: ipv4-address.h:40
The attribute can be read.
Definition: type-id.h:63
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
Returns the protocol number of this protocol.
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:1274
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:356
Ipv4EndPoint * Allocate(void)
Allocate an IPv4 Endpoint.
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.
static const uint32_t packetSize
tuple address
Definition: first.py:37
virtual void NotifyNewAggregate(void)
Notify all Objects aggregated to this one of a new Object being aggregated.
Definition: object.cc:325
Ptr< const AttributeAccessor > MakeStringAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method...
Definition: string.h:42
Container for a set of ns3::Object pointers.
virtual void gettime(unsigned int *, unsigned int *)
Called by the Linux stack RNG initialization.
a unique identifier for an interface.
Definition: type-id.h:58
void * m_dlopenHandle
dynamic library handle.
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:904
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:257
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.