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 
bool IsNull(void) const
Check for null implementation.
Definition: callback.h:1386
void Nullify(void)
Discard the implementation, set it to null.
Definition: callback.h:1391
L4 Protocol abstract base class.
RxStatus
Rx status codes.
Ipv4 addresses are stored in host order in this class.
Definition: ipv4-address.h:41
void Print(std::ostream &os) const
Print this address to the given output stream.
Demultiplexes packets to various transport layer endpoints.
EndPoints GetAllEndPoints(void)
Get the entire list of end points registered.
std::list< Ipv4EndPoint * > EndPoints
Container of the IPv4 endpoints.
Ipv4EndPoint * Allocate(void)
Allocate a Ipv4EndPoint.
std::list< Ipv4EndPoint * >::iterator EndPointsI
Iterator to the container of the IPv4 endpoints.
A representation of an internet endpoint/connection.
Packet header for IPv4.
Definition: ipv4-header.h:34
void SetDestination(Ipv4Address destination)
Definition: ipv4-header.cc:298
void SetPayloadSize(uint16_t size)
Definition: ipv4-header.cc:56
Ipv4Address GetSource(void) const
Definition: ipv4-header.cc:291
void SetTtl(uint8_t ttl)
Definition: ipv4-header.cc:259
Ipv4Address GetDestination(void) const
Definition: ipv4-header.cc:304
void EnableChecksum(void)
Enable checksum calculation for this header.
Definition: ipv4-header.cc:49
void SetProtocol(uint8_t num)
Definition: ipv4-header.cc:278
void SetSource(Ipv4Address source)
Definition: ipv4-header.cc:285
Access to the IPv4 forwarding table, interfaces, and configuration.
Definition: ipv4.h:77
a class to store IPv4 address information on an interface
Ipv4Mask GetMask(void) const
Get the network mask.
Ipv4Address GetLocal(void) const
Get the local address.
Implement the IPv4 layer.
void Send(Ptr< Packet > packet, Ipv4Address source, Ipv4Address destination, uint8_t protocol, Ptr< Ipv4Route > route)
a class to represent an Ipv4 address mask
Definition: ipv4-address.h:269
void Print(std::ostream &os) const
Print this mask to the given output stream.
Packet header for IPv6.
Definition: ipv6-header.h:35
Nsc interface implementation class.
virtual void gettime(unsigned int *sec, unsigned int *usec)
Called by the Linux stack RNG initialization.
Ptr< NscTcpL4Protocol > m_prot
the NSC TCP protocol
NscInterfaceImpl(Ptr< NscTcpL4Protocol > prot)
Constructor.
virtual void send_callback(const void *data, int datalen)
Invoked by NSCs 'ethernet driver' to re-inject a packet into ns-3.
virtual void wakeup()
Called by the NSC stack whenever something of interest has happened.
Nsc wrapper glue, to interface with the Ipv4 protocol underneath.
Timer m_softTimer
Soft interrupt timer.
Ptr< Node > m_node
the node this stack is associated with
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...
static TypeId GetTypeId(void)
Get the type ID.
std::string m_nscLibrary
path to the NSC library.
std::string GetNscLibrary(void) const
Get the NSC library being used.
virtual void NotifyNewAggregate()
Notify all Objects aggregated to this one of a new Object being aggregated.
void AddInterface(void)
Add an interface.
Ptr< Socket > CreateSocket(void)
void SetNode(Ptr< Node > node)
Set node associated with this stack.
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...
Ipv4EndPointDemux * m_endPoints
A list of IPv4 end points.
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.
void send_callback(const void *data, int datalen)
Invoked by NSCs 'ethernet driver' to re-inject a packet into ns-3.
void gettime(unsigned int *sec, unsigned int *usec)
Called by the Linux stack RNG initialization.
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...
IpL4Protocol::DownTargetCallback m_downTarget
Callback to send packets over IPv4.
void DeAllocate(Ipv4EndPoint *endPoint)
Remove an IPv4 Endpoint.
Ipv4EndPoint * Allocate(void)
Allocate an IPv4 Endpoint.
void SoftInterrupt(void)
Provide a "soft" interrupt to NSC.
NscInterfaceImpl * m_nscInterface
the NSC Interface.
void SetNscLibrary(const std::string &lib)
Set the NSC library to be used.
virtual void DoDispose(void)
Destructor implementation.
std::vector< Ptr< NscTcpSocketImpl > > m_sockets
list of sockets
void wakeup()
Called by the NSC stack whenever something of interest has happened.
INetStack * m_nscStack
the NSC stack.
void * m_dlopenHandle
dynamic library handle.
virtual int GetVersion(void) const
Get the NSC version.
static const uint8_t PROT_NUMBER
protocol number (0x6)
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...
virtual int GetProtocolNumber(void) const
Returns the protocol number of this protocol.
virtual void NotifyNewAggregate(void)
Notify all Objects aggregated to this one of a new Object being aggregated.
Definition: object.cc:325
virtual void DoDispose(void)
Destructor implementation.
Definition: object.cc:346
void AggregateObject(Ptr< Object > other)
Aggregate two Objects together.
Definition: object.cc:252
Ptr< T > GetObject(void) const
Get a pointer to the requested aggregated Object.
Definition: object.h:470
Container for a set of ns3::Object pointers.
void AddHeader(const Header &header)
Add header to this packet.
Definition: packet.cc:256
uint32_t CopyData(uint8_t *buffer, uint32_t size) const
Copy the packet contents to a byte buffer.
Definition: packet.cc:378
uint32_t GetSize(void) const
Returns the the size in bytes of the packet (including the zero-filled initial payload).
Definition: packet.h:852
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:74
static EventId ScheduleNow(FUNC f, Ts &&... args)
Schedule an event to expire Now.
Definition: simulator.h:588
static Time Now(void)
Return the current simulation virtual time.
Definition: simulator.cc:195
Hold variables of type string.
Definition: string.h:41
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:104
int64_t GetMicroSeconds(void) const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:388
A simple virtual Timer class.
Definition: timer.h:74
void SetDelay(const Time &delay)
Definition: timer.cc:75
void SetFunction(FN fn)
Definition: timer.h:278
void Schedule(void)
Schedule a new event using the currently-configured delay, function, and arguments.
Definition: timer.cc:158
a unique identifier for an interface.
Definition: type-id.h:59
@ ATTR_GET
The attribute can be read.
Definition: type-id.h:64
@ ATTR_CONSTRUCT
The attribute can be written at construction-time.
Definition: type-id.h:66
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:923
uint16_t port
Definition: dsdv-manet.cc:45
#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
#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
Ptr< const AttributeAccessor > MakeObjectVectorAccessor(U T::*memberVariable)
MakeAccessorHelper implementation for ObjectVector.
Definition: object-vector.h:81
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
Ptr< const AttributeChecker > MakeStringChecker(void)
Definition: string.cc:30
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:165
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:205
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition: log.h:289
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:45
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1297
address
Definition: first.py:44
Every class exported by the ns3 library is enclosed in the ns3 namespace.
int external_rand()
External Random number generator.
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
INetStack *(* FCreateStack)(ISendCallback *, IInterruptCallback *, FRandom)
uint8_t data[writeSize]
Struct interface to NSC soft interrupt capabilities.
virtual int get_hz()=0
Get the timer_interrupt frequency.
virtual void init(int hz)=0
Initialize the stack.
virtual void if_receive_packet(int if_id, const void *data, int datalen)=0
Deliver complete packet to the NSC network stack.
virtual void add_default_gateway(const char *addr)=0
Add a default gateway to the interface.
virtual void increment_ticks()=0
Increment the time ticks.
virtual void if_attach(const char *addr, const char *mask, int mtu)=0
Attach an interface to the stack.
virtual void timer_interrupt()=0
The stack timer_interrupt function.
virtual void if_send_finish(int if_id)=0
Signal the completion of send procedure to the NSC network stack.
Struct interface to NSC send capabilities.
static const uint32_t packetSize