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 << boundNetDevice << port);
315  return m_endPoints->Allocate (boundNetDevice, port);
316 }
317 
318 Ipv4EndPoint *
320 {
321  NS_LOG_FUNCTION (this << boundNetDevice << address << port);
322  return m_endPoints->Allocate (boundNetDevice, address, port);
323 }
324 
325 Ipv4EndPoint *
327  Ipv4Address localAddress, uint16_t localPort,
328  Ipv4Address peerAddress, uint16_t peerPort)
329 {
330  NS_LOG_FUNCTION (this << boundNetDevice << localAddress << localPort << peerAddress << peerPort);
331  return m_endPoints->Allocate (boundNetDevice,
332  localAddress, localPort,
333  peerAddress, peerPort);
334 }
335 
336 void
338 {
339  NS_LOG_FUNCTION (this << endPoint);
340  // NSC m_endPoints->DeAllocate (endPoint);
341 }
342 
345  Ipv4Header const &header,
346  Ptr<Ipv4Interface> incomingInterface)
347 {
348  NS_LOG_FUNCTION (this << packet << header << incomingInterface);
349  Ipv4Header ipHeader;
350  uint32_t packetSize = packet->GetSize ();
351 
352  // The way things work at the moment, the IP header has been removed
353  // by the ns-3 IPv4 processing code. However, the NSC stack expects
354  // a complete IP packet, so we add the IP header back.
355  // Since the original header is already gone, we create a new one
356  // based on the information we have.
357  ipHeader.SetSource (header.GetSource ());
358  ipHeader.SetDestination (header.GetDestination ());
359  ipHeader.SetProtocol (PROT_NUMBER);
360  ipHeader.SetPayloadSize (packetSize);
361  ipHeader.SetTtl (1);
362  // all NSC stacks check the IP checksum
363  ipHeader.EnableChecksum ();
364 
365  packet->AddHeader (ipHeader);
366  packetSize = packet->GetSize ();
367 
368  uint8_t *buf = new uint8_t[packetSize];
369  packet->CopyData (buf, packetSize);
370  const uint8_t *data = const_cast<uint8_t *>(buf);
371 
372  // deliver complete packet to the NSC network stack
373  m_nscStack->if_receive_packet (0, data, packetSize);
374  delete[] buf;
375 
376  wakeup ();
377  return IpL4Protocol::RX_OK;
378 }
379 
382 {
384 }
385 
387 {
391 }
392 
393 void NscTcpL4Protocol::send_callback (const void* data, int datalen)
394 {
395  Ptr<Packet> p;
396  uint32_t ipv4Saddr, ipv4Daddr;
397 
398  NS_ASSERT (datalen > 20);
399 
400 
401  // create packet, without IP header. The TCP header is not touched.
402  // Not using the IP header makes integration easier, but it destroys
403  // eg. ECN.
404  const uint8_t *rawdata = reinterpret_cast<const uint8_t *>(data);
405  rawdata += 20; // skip IP header. IP options aren't supported at this time.
406  datalen -= 20;
407  p = Create<Packet> (rawdata, datalen);
408 
409  // we need the real source/destination ipv4 addresses for Send ().
410  const uint32_t *ipheader = reinterpret_cast<const uint32_t *>(data);
411  ipv4Saddr = *(ipheader+3);
412  ipv4Daddr = *(ipheader+4);
413 
414  Ipv4Address saddr (ntohl (ipv4Saddr));
415  Ipv4Address daddr (ntohl (ipv4Daddr));
416 
418  NS_ASSERT_MSG (ipv4, "nsc callback invoked, but node has no ipv4 object");
419 
420  m_downTarget (p, saddr, daddr, PROT_NUMBER, 0);
422 }
423 
425 {
426  // \todo
427  // this should schedule a timer to read from all tcp sockets now... this is
428  // an indication that data might be waiting on the socket
429 
431  for (Ipv4EndPointDemux::EndPointsI endPoint = endPoints.begin ();
432  endPoint != endPoints.end (); endPoint++) {
433  // NSC HACK: (ab)use TcpSocket::ForwardUp for signalling
434  (*endPoint)->ForwardUp (NULL, Ipv4Header (), 0, 0);
435  }
436 }
437 
438 void NscTcpL4Protocol::gettime (unsigned int* sec, unsigned int* usec)
439 {
440  // Only used by the Linux network stack, e.g. during ISN generation
441  // and in the kernel rng initialization routine. Also used in Linux
442  // printk output.
443  Time t = Simulator::Now ();
444  int64_t us = t.GetMicroSeconds ();
445  *sec = us / (1000*1000);
446  *usec = us - *sec * (1000*1000);
447 }
448 
449 
451 {
452  Ptr<Ipv4> ip = m_node->GetObject<Ipv4> ();
453  const uint32_t nInterfaces = ip->GetNInterfaces ();
454 
455  NS_ASSERT_MSG (nInterfaces <= 2, "nsc does not support multiple interfaces per node");
456 
457  // start from 1, ignore the loopback interface (HACK)
458  // we really don't need the loop, but its here to illustrate
459  // how things _should_ be (once nsc can deal with multiple interfaces...)
460  for (uint32_t i = 1; i < nInterfaces; i++)
461  {
462  Ipv4InterfaceAddress ifAddr = ip->GetAddress (i, 0);
463  Ipv4Address addr = ifAddr.GetLocal ();
464  Ipv4Mask mask = ifAddr.GetMask ();
465  uint16_t mtu = ip->GetMtu (i);
466 
467  std::ostringstream addrOss, maskOss;
468 
469  addr.Print (addrOss);
470  mask.Print (maskOss);
471 
472  NS_LOG_LOGIC ("if_attach " << addrOss.str ().c_str () << " " << maskOss.str ().c_str () << " " << mtu);
473 
474  std::string addrStr = addrOss.str ();
475  std::string maskStr = maskOss.str ();
476  const char* addrCStr = addrStr.c_str ();
477  const char* maskCStr = maskStr.c_str ();
478  m_nscStack->if_attach (addrCStr, maskCStr, mtu);
479 
480  if (i == 1)
481  {
482  // The NSC stack requires a default gateway and only supports
483  // single-interface nodes. The below is a hack, but
484  // it turns out that we can pass the interface address to nsc as
485  // a default gateway. Bug 1398 has been opened to track this
486  // issue (NSC's limitation to single-interface nodes)
487  //
488  // Previous versions of this code tried to assign the "next"
489  // IP address of the subnet but this was found to fail for
490  // some use cases in /30 subnets.
491 
492  // \todo \bugid{1398} NSC's limitation to single-interface nodes
493  m_nscStack->add_default_gateway (addrOss.str ().c_str ());
494  }
495  }
496 }
497 
498 void
500 {
501  m_downTarget = callback;
502 }
503 
504 void
506 {
507 }
508 
511 {
512  return m_downTarget;
513 }
514 
517 {
519 }
520 
521 } // namespace ns3
522 
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:45
Ipv4Address GetLocal(void) const
Get the local address.
Ptr< T > GetObject(void) const
Get a pointer to the requested aggregated Object.
Definition: object.h:459
Hold variables of type string.
Definition: string.h:41
a class to represent an Ipv4 address mask
Definition: ipv4-address.h:258
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:202
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1015
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:831
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
The attribute can be written at construction-time.
Definition: type-id.h:65
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:45
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:63
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.
NS_ASSERT_MSG(false,"Ipv4AddressGenerator::MaskToIndex(): Impossible")
int64_t GetMicroSeconds(void) const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:363
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
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.
address
Definition: first.py:37
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:1570
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:249
void Print(std::ostream &os) const
Print this mask to the given output stream.
NS_LOG_LOGIC("Net device "<< nd<< " is not bridged")
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
Ipv4EndPointDemux * m_endPoints
A list of IPv4 end points.
Ipv4 addresses are stored in host order in this class.
Definition: ipv4-address.h:40
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:378
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.
static const uint32_t packetSize
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:915
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: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 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 &#39;ethernet driver&#39; to re-inject a packet into ns-3.
Ipv4EndPoint * Allocate(void)
Allocate a Ipv4EndPoint.