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
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 
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
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 "...
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
uint32_t GetSize(void) const
Returns the the size in bytes of the packet (including the zero-filled initial payload).
Definition: packet.h:852
NS_ASSERT_MSG(false, "Ipv4AddressGenerator::MaskToIndex(): Impossible")
Hold variables of type string.
Definition: string.h:41
a class to represent an Ipv4 address mask
Definition: ipv4-address.h:263
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:1072
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:162
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.
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.
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:1610
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
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:461
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:363
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.
static EventId ScheduleNow(MEM mem_ptr, OBJ obj)
Schedule an event to expire Now.
Definition: simulator.h:1579
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:193
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
Ipv4Address GetDestination(void) const
Definition: ipv4-header.cc:304
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:1377
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 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.
virtual void gettime(unsigned int *, unsigned int *)
Called by the Linux stack RNG initialization.
bool IsNull(void) const
Check for null implementation.
Definition: callback.h:1372
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:922
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 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.