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 ();
97  virtual void gettime (unsigned int *sec, unsigned int *usec);
98 private:
100 };
101 
103  : m_prot (prot)
104 {
105 }
106 
107 void
108 NscInterfaceImpl::send_callback (const void *data, int datalen)
109 {
110  m_prot->send_callback (data, datalen);
111 }
112 void
114 {
115  m_prot->wakeup ();
116 }
117 void
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
130 {
131  static TypeId tid = TypeId ("ns3::NscTcpL4Protocol")
133  .SetGroupName ("Internet")
134  .AddConstructor<NscTcpL4Protocol>()
135  .AddAttribute ("SocketList", "The list of sockets associated to this protocol.",
138  MakeObjectVectorChecker<NscTcpSocketImpl> ())
139  .AddAttribute ("Library",
140  "Set the linux library to be used to create the stack",
142  StringValue ("liblinux2.6.26.so"),
145  ;
146  return tid;
147 }
148 
157 {
158  return 1;
159 }
160 
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 
172 {
173  NS_LOG_FUNCTION (this);
174  dlclose (m_dlopenHandle);
175 }
176 
177 void
178 NscTcpL4Protocol::SetNscLibrary (const std::string &soname)
179 {
180  if (soname!="")
181  {
182  m_nscLibrary = soname;
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
192 {
193  return m_nscLibrary;
194 }
195 void
197 {
198  m_node = node;
199 
200  if (m_nscStack)
201  { // stack has already been loaded...
202  return;
203  }
204 
206 
207  FCreateStack create = (FCreateStack)dlsym (m_dlopenHandle, "nsc_create_stack");
208  NS_ASSERT (create);
210  int hzval = m_nscStack->get_hz ();
211 
212  NS_ASSERT (hzval > 0);
213 
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 
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.
229 }
230 
231 void
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);
248  }
249  }
250  }
252 }
253 
254 int
256 {
257  return PROT_NUMBER;
258 }
259 int
261 {
262  return 2;
263 }
264 
265 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;
287 }
288 
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 *
303 {
304  NS_LOG_FUNCTION (this);
305  return m_endPoints->Allocate ();
306 }
307 
308 Ipv4EndPoint *
310 {
311  NS_LOG_FUNCTION (this << address);
312  return m_endPoints->Allocate (address);
313 }
314 
315 Ipv4EndPoint *
317 {
318  NS_LOG_FUNCTION (this << boundNetDevice << port);
319  return m_endPoints->Allocate (boundNetDevice, port);
320 }
321 
322 Ipv4EndPoint *
324 {
325  NS_LOG_FUNCTION (this << boundNetDevice << address << port);
326  return m_endPoints->Allocate (boundNetDevice, address, port);
327 }
328 
329 Ipv4EndPoint *
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
342 {
343  NS_LOG_FUNCTION (this << endPoint);
344  // NSC m_endPoints->DeAllocate (endPoint);
345 }
346 
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
378  delete[] buf;
379 
380  wakeup ();
381  return IpL4Protocol::RX_OK;
382 }
383 
386 {
388 }
389 
391 {
395 }
396 
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 
422  NS_ASSERT_MSG (ipv4, "nsc callback invoked, but node has no ipv4 object");
423 
424  m_downTarget (p, saddr, daddr, PROT_NUMBER, 0);
426 }
427 
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 
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 
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 
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
504 {
505  m_downTarget = callback;
506 }
507 
508 void
510 {
511 }
512 
515 {
516  return m_downTarget;
517 }
518 
521 {
523 }
524 
525 } // namespace ns3
526 
std::string GetNscLibrary(void) const
Get the NSC library being used.
void SetSource(Ipv4Address source)
Definition: ipv4-header.cc:285
void SetPayloadSize(uint16_t size)
Definition: ipv4-header.cc:56
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:103
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 "...
virtual void wakeup()
Called by the NSC stack whenever something of interest has happened.
A simple virtual Timer class.
Definition: timer.h:73
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:45
uint32_t GetSize(void) const
Returns the the size in bytes of the packet (including the zero-filled initial payload).
Definition: packet.h:852
Hold variables of type string.
Definition: string.h:41
a class to represent an Ipv4 address mask
Definition: ipv4-address.h:269
static const uint32_t packetSize
void AggregateObject(Ptr< Object > other)
Aggregate two Objects together.
Definition: object.cc:252
IpL4Protocol::DownTargetCallback m_downTarget
Callback to send packets over IPv4.
Ipv4Address GetSource(void) const
Definition: ipv4-header.cc:291
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:205
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1297
Ptr< Socket > CreateSocket(void)
int external_rand()
External Random number generator.
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:165
virtual void DoDispose(void)
Destructor implementation.
Definition: object.cc:346
The attribute can be written at construction-time.
Definition: type-id.h:66
void SetProtocol(uint8_t num)
Definition: ipv4-header.cc:278
void wakeup()
Called by the NSC stack whenever something of interest has happened.
void SetNscLibrary(const std::string &lib)
Set the NSC library to be used.
uint16_t port
Definition: dsdv-manet.cc:45
virtual void increment_ticks()=0
Increment the time ticks.
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:64
NscInterfaceImpl(Ptr< NscTcpL4Protocol > prot)
Constructor.
Ptr< const AttributeChecker > MakeStringChecker(void)
Definition: string.cc:30
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.
static EventId ScheduleNow(FUNC f, Ts &&... args)
Schedule an event to expire Now.
Definition: simulator.h:588
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:278
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.
void Send(Ptr< Packet > packet, Ipv4Address source, Ipv4Address destination, uint8_t protocol, Ptr< Ipv4Route > route)
Ptr< NscTcpL4Protocol > m_prot
the NSC TCP protocol
Ipv4Mask GetMask(void) const
Get the network mask.
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:289
Access to the IPv4 forwarding table, interfaces, and configuration.
Definition: ipv4.h:76
Ptr< T > GetObject(void) const
Get a pointer to the requested aggregated Object.
Definition: object.h:470
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...
int64_t GetMicroSeconds(void) const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:388
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.
address
Definition: first.py:44
INetStack *(* FCreateStack)(ISendCallback *, IInterruptCallback *, FRandom)
Nsc interface implementation class.
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:195
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
Ipv4Address GetDestination(void) const
Definition: ipv4-header.cc:304
#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:88
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...
Ipv4EndPointDemux * m_endPoints
A list of IPv4 end points.
Ipv4 addresses are stored in host order in this class.
Definition: ipv4-address.h:41
std::list< Ipv4EndPoint * > EndPoints
Container of the IPv4 endpoints.
virtual int GetVersion(void) const
Get the NSC version.
std::vector< Ptr< NscTcpSocketImpl > > m_sockets
list of sockets
a class to store IPv4 address information on an interface
virtual int GetProtocolNumber(void) const
Returns the protocol number of this protocol.
void DeAllocate(Ipv4EndPoint *endPoint)
Remove an IPv4 Endpoint.
uint32_t CopyData(uint8_t *buffer, uint32_t size) const
Copy the packet contents to a byte buffer.
Definition: packet.cc:378
void SetTtl(uint8_t ttl)
Definition: ipv4-header.cc:259
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...
virtual void if_attach(const char *addr, const char *mask, int mtu)=0
Attach an interface to the stack.
Ipv4Address GetLocal(void) const
Get the local address.
void Nullify(void)
Discard the implementation, set it to null.
Definition: callback.h:1391
std::list< Ipv4EndPoint * >::iterator EndPointsI
Iterator to the container of the IPv4 endpoints.
Ipv4EndPoint * Allocate(void)
Allocate an IPv4 Endpoint.
RxStatus
Rx status codes.
virtual void gettime(unsigned int *sec, unsigned int *usec)
Called by the Linux stack RNG initialization.
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.
void Print(std::ostream &os) const
Print this address to the given output stream.
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.
bool IsNull(void) const
Check for null implementation.
Definition: callback.h:1386
a unique identifier for an interface.
Definition: type-id.h:58
void Print(std::ostream &os) const
Print this mask to the given output stream.
void * m_dlopenHandle
dynamic library handle.
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:923
void gettime(unsigned int *sec, unsigned int *usec)
Called by the Linux stack RNG initialization.
Callback< R, Ts... > MakeCallback(R(T::*memPtr)(Ts...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition: callback.h:1642
Timer m_softTimer
Soft interrupt timer.
void AddHeader(const Header &header)
Add header to this packet.
Definition: packet.cc:256
A representation of an internet endpoint/connection.
void send_callback(const void *data, int datalen)
Invoked by NSCs &#39;ethernet driver&#39; to re-inject a packet into ns-3.
virtual void send_callback(const void *data, int datalen)
Invoked by NSCs &#39;ethernet driver&#39; to re-inject a packet into ns-3.
Ipv4EndPoint * Allocate(void)
Allocate a Ipv4EndPoint.