Skip to main content

OTCL and C++ Linkages with Example - NS2 Tutorial 3

OTcl and C++ Linkages

In this post

  • The linkages between OTcl and C++ is covered.
  • The functions of various TclCL classes were explored.

Network simulator 2 (ns) deals with two different languages OTcl and C++. The OTcl is mainly for beginners that act as a frontend to test, analyze the components of networks. But C++ on the other hand runs in the background and usually deals with implementation of Queues, protocols, packets, agents, applications, etc. However when C++ modules are introduced, it is necessary to see how it is linking with the OTcl objects. This chapter deals this.

 

3.1 NS-2 Architecture

Network Simulator 2 (NS-2) deals with two different languages C++ and OTcl.  Mainly OTcl is interpreted language and C++ is Compiled language.

The advantage of both the languages in NS2 is not compromised as both the languages have their own pros and cons.

OTcl  

·       Preferable for beginners (to start simulation even without knowing much about ns2)

·       Runs in the front end. (Since interpreter is slow in execution, OTcl preferred in the front end)

·       Interpretation is fast and execution is slow (Since it accepts changes fast, the source code can be modified easily to verify the network performance)

C++

·       Mainly deals with implementation of network terminologies like queues, packets, agents, applications, routing algorithms, etc.

·       Preferable for medium and advanced users

·       Its execution is fast and compilation is slow. (Compilers usually are slow in compilation and hence they are running in the background to make the execution faster)

With these above, we can conclude that OTcl and C++ both need to be in their places for faster execution.

3.2 Code Overview

Consider the example:

        set tcp1 [new Agent/TCP]

     set sink1 [new Agent/TCPSink]

set udp1 [new Agent/UDP]

The above code is a Tcl code that calls TcpAgent, TCPSink Agent and FTP Application. All three are C++ modules that are executing in the backend.

These three Tcl Objects links with the C++ Objects as given in the Table

OTcl Object

C++ Class

Location of C++ file

Agent/TCP

TcpClass

~ns-2.35/tcp/tcp.cc

Agent/TCPSink

TcpSinkClass

~ns-2.35/tcp/tcp-sink.cc

Agent/UDP

UdpAgentClass

~ns-2.35/apps/udp.cc

 

As shown in the table, there should be a link between the OTcl and C++. NS-2 defines a interface called TclCL (~tclcl/) that contains some classes that makes the mapping between OTcl and C++.

There are some lists of classes and this chapter will be focusing on four main classes with their member functions. These classes are defined in ~tclcl-xx/Tcl.h. The following table lists the purpose of each class with their class names

Tcl

Contains method to access the interpreter

TclObject

This is the base class of all Simulated object libraries

TclClass

Provides the mapping between the classes of interpreted hierarchy and compiled hierarchy

TclCommand

Used to define the global interpreter command

EmbeddedTcl

Contains method to load the C++ commands for easier configuration

InstVar

Contains methods to access C++ member variables as OTcl instance variables.

 

The location of these classes are found in the ~tclcl/Tcl.[h, .cc], ~tclcl/Tcl2.cc, ~tclcl/tcl-object.tcl, etc. These classes are used in building ns.

Class Tcl

The class Tcl that contains methods to access the interpreted hierarchy. The methods can be used by the programmer to develop the C++ code.

Class Tcl provides the following operations

·       Obtain a reference to Tcl instance

o   Tcl& tcl = Tcl::instance();

o   tcl is the reference and all the methods can be accessed using tcl.eval(), tcl.evalf(), etc.

·       Invoke Tcl procedures

o   Four methods are there to invoke the command through the instance tcl.

o   tcl.eval() -

o   tcl.eval(char* a) – executes ‘a’ through the interpreter.

o   tcl.evalf(const char* a…..)- this is similar like a printf() statement where the format specifiers are used.

o   tcl.evalc(const char* a)- it preserves the argument string ‘a’ as a constant.

Example:

tcl.evalf(“%d is the packet id”, packet_id);

tcl.evalc(“put this to the screen”);

·       Passing Results to/from the Interpreter

o   Two functions are used to pass results to/from the interpreter.

o   tcl.result(const char* a) – pass the string a to the interpreter back.

o   tcl.resultf(const char* fmt, ...)

o   the following script will help you on this

if (strcmp(argv[1], "HELLO") == 0)

{

tcl.resultf("%d", seq_no);

return TCL_OK;

}

tcl.result("Invalid operation specified");

return TCL_ERROR;

·       Error Reporting and Exit

o   Errors are often reported to the interpreter using the function error().

o   tcl.error(const char* a) performs the following functions:

§  write a to stdout;

§  write tcl_->result to stdout;

§  exit with error code 1.

·       There are other operations and hash Functions within the Interpreter, they are

o   tcl.enter(TclObject* o) – to insert an object in the hash table while creating the TclObject

o   tcl.lookup(char* a) will retrieve the TclObject with the name a.

o   tcl.remove(TclObject* o) will delete references to the TclObject.

o   These functions are used internally by the class TclObject and class TclClass.

 

Class TclClass and Class TclObject

TclClass is a pure virtual class. Classes derived from this base class provide two functions:

·       It does the mapping between the classes of interpreted hierarchy and compiled hierarchy;

·       This class provides methods to create instance for TclObject.

// ~ns-2.35/tcp/tcp.cc

static class TcpClass : public TclClass {

public:

            TcpClass() : TclClass("Agent/TCP") {}

            TclObject* create(int , const char*const*) {

                        return (new TcpAgent());

            }

       } class_tcp;

As an example, consider the code segment above which shows the syntax of the TcpClass. It is derived from class TclClass, and is associated with the class TcpAgent. This will will create the instance of TcpAgent and thus create new objects in the class TcpAgent. The compiled class hierarchy for TcpAgent is that it derives from Agent, that in turn derives from TclObject.

Here is the observation from this definition:

·       This TclClass defines only the constructor and it shows the compiled hierarchy.

·       ns will execute the TcpClass constructor for the static variable class_tcp, when it is first started.

·       The constructor specifies the interpreted class explicitly as Agent/TCP. This also specifies the interpreted hierarchy.

·       The convention in ns is to use the character slash (’/’) is a separator. For any given class A/B/C/D, the class A/B/C/D is a sub-class of A/B/C that is itself a sub-class of A/B, that, in turn, is a sub-class of A. and A is the sub class of TclObject. In our case above, the TclClass constructor creates two classes, Agent/TCP sub-class of Agent sub- class of TclObject.

·       The TcpClass::create method returns TclObject in the class TcpAgent.

·       When the user specifies new Agent/TCP in the tcl file, the class TcpClass::create is invoked and thus a shadow object is created.

Consider the Example shown called as the Amplifier Agent that amplifies the given value in to multiples times

/* A Simple agent that does the amplification of a given value to 3 fold and more. The name of the agent is represented as TSPAgent as The SPecial Agent that does the amplification */

//Header file declaration

#include <stdio.h>

#include <string.h>

#include "agent.h"

class TSPAgent : public Agent {

public:

                  TSPAgent();

protected:

      int command(int argc, const char*const* argv);

private:

      int    amp1, amp2, amp3;

      void   APrivateFunc(void);

};

 

static class TSPAgentClass : public TclClass {

public:

      TSPAgentClass() : TclClass("Agent/AMPLIFY") {}

      TclObject* create(int, const char*const*) {

return(new TSPAgent());

      }

} class_tsp_agent;

 

TSPAgent::TSPAgent() : Agent(PT_UDP) {

      bind("Ampli1", &amp1);

      bind("Ampli2", &amp2);

      bind("Ampli3", &amp3);

}

int TSPAgent::command(int argc, const char*const* argv) {

      if(argc == 2) {

                  if(strcmp(argv[1], "call-the-private-function") == 0) {

            APrivateFunc();

            return(TCL_OK);

                  }

      }

      return(Agent::command(argc, argv));

}

void TSPAgent::APrivateFunc(void) {

      Tcl& tcl = Tcl::instance();

      tcl.eval("puts \"Message From the Private Function\"");

      tcl.evalf("puts \"  The Amplified Value is %d and the factor is 2 \"", amp1*amp1);

      tcl.evalf("puts \"  The Amplified Value is %d and the factor is 3 \"", amp2*amp2*amp2);

      tcl.evalf("puts \"  The Amplified Value is %d and the factor is 4 \"", amp3*amp3*amp3*amp3);

}

In the above example, the Line 1 to 3, includes the header files, the Agent class is available in the agent.h file.

Line 5 to 13, declares a class with three integer variables and two functions command() and APrivateFunc().

Line 14 to 19, includes a static class that does the mapping between the OTCL and C++ and also contains the code that instantiates the TclObject. The name of the Agent here is Agent/AMPLIFY which indicates it is a interpreted hierarchy and the static class TSPAgentClass is the compiled hierarchy class. Clearly, the TclClass does the mapping between the Interpreted hierarchy and Compiled hierarchy.

Line 20 to 24, declares the constructor and all the agents should act on a Packet, so this agent acts in the UDP Packet, PT_UDP. There are three binding OTCL factors Ampli1, Ampli2 and Ampli3 that maps to C++’s amp1, amp2 and amp3 respectively.

 Line 25 to 31, implements the command function, that processes the arguments passed from the OTCL.  If the argv[1] and the call-the-private-function is validated, that calls the APrivateFunc();

Line 32 to 38, the implementation of APrivateFunc() that amplifies the values.

Here is the Tcl file to test the above agent

 

#the name of the file is agent.tcl

set myagent [new Agent/AMPLIFY]

$myagent set Ampli1 3

$myagent set Ampli2 4

$myagent set Ampli3 5

$myagent call-the-private-function

To execute the above agent, here are the steps

·       Copy the ampagent.cc file in ~ns-allinone-2.35/ns-2.35/newagent

·       Make an entry in the ~ns-2.35/Makefile.in

            Make an entry in the OBJ_CC =

                                    newfolder/ampagent.o \

·       In the shell prompt, go to ~ns-2.35 and give the following commands one by one

./configure

Make

·       Run the file agent.tcl

·       If warnings are there, the set the default values in the ns-default.tcl file (~ns-2.35/tcl/lib) as shown below

o   Agent/AMPLIFY set Ampli1 1

o   Agent/AMPLIFY set Ampli2 1

o   Agent/AMPLIFY set Ampli3 1

Output:

Message From the Private Function

  The Amplified Value is 9 and the factor is 2

  The Amplified Value is 64 and the factor is 3

  The Amplified Value is 625 and the factor is 4

Comments

Popular posts from this blog

Installing ns-3.34 in Ubuntu 20.04

This post shows how to install ns 3.34 in Ubuntu 20.04 LTS Prerequisites: Fresh installation of Ubuntu Version 20.04 LTS  ns3.34 can be downloaded from here Follow the video link for complete step by step instructions on the installation.  This version fixes the compilation issues of vanet-routing-compare.cc (bug in ns3.33)  Issue the following commands after opening a terminal  $ sudo apt update $ sudo apt install g++ python3 python3-dev python-dev pkg-config sqlite3 python3-setuptools git qt5-default gir1.2-goocanvas-2.0 python3-gi python3-gi-cairo python3-pygraphviz gir1.2-gtk-3.0 ipython3 openmpi-bin openmpi-common openmpi-doc libopenmpi-dev autoconf cvs bzr unrar openmpi-bin openmpi-common openmpi-doc libopenmpi-dev tcpdump wireshark libxml2 libxml2-dev Unzip or untar the ns-allinone-3.34.tar.bz2 in the home folder (in my case its /home/pradeepkumar) $ cd ns-allinone-3.34/ $ ./build.py --enable-examples --enable-tests  Once the installation is completed, you may get an output show

Installation of NS2 (ns-2.35) in Ubuntu 20.04

Installation of NS2 (ns-2.35) in Ubuntu 20.04 LTS Step 1: Install the basic libraries like      $] sudo apt install build-essential autoconf automake libxmu-dev Step 2: install gcc-4.8 and g++-4.8 open the file using sudo mode $] sudo nano /etc/apt/sources.list Include the following line deb http://in.archive.ubuntu.com/ubuntu bionic main universe $] sudo apt update $] sudo apt install gcc-4.8 g++-4.8 Step 3:  Unzip the ns2 packages to home folder $] tar zxvf ns-allinone-2.35.tar.gz $] cd ns-allinone-2.35/ns-2.35 Modify the following make files. ~ns-2.35/Makefile.in Change @CC@ to gcc-4.8 change @CXX@ to g++-4.8 ~nam-1.15/Makefile.in ~xgraph-12.2/Makefile.in ~otcl-1.14/Makefile.in Change in all places  @CC@ to gcc-4.8 @CPP@ or @CXX@ to g++-4.8 open the file: ~ns-2.35/linkstate/ls.h Change at the Line no 137  void eraseAll() { erase(baseMap::begin(), baseMap::end()); } to This void eraseAll() { this->erase(baseMap::begin(), baseMap::end()); } All changes made Step 4: Open a new termi

Installation of ns3 in Windows 10 and Windows 11 OS using WSL (Windows Subsystem for Linux)

This post shows how to install ns-3.33 in Windows 10 through WSL (Windows Subsystem for Linux) This posts works for Windows 11 also (I have tested it on a Windows 11 ISO and it works the Same way as mentioned in the following post.) This post will work for ns-3.3x version. Prerequisites : Install Windows Subsystem for Linux with GUI: Please refer the following video  System Information: OS used: Windows 10 and WSL (Ubuntu 20.04) GUI: XServer for Windows NS3 Version: ns-3.33 See the following complete video on how to install ns3 in Windows 10 Step 0 : Open XLaunch Step 1 :  Open WSL using PowerShell and open it as Administrator Command:/  wsl $ xfce4-session The GUI of Ubuntu Opens within Windows 10 OS. Step 2 : Download ns3 from nsnam.org website through Mozilla Firefox browser Step 3: Open a Terminal  $ sudo apt update $ sudo apt install build-essential autoconf automake libxmu-dev python3-pygraphviz cvs mercurial bzr git cmake p7zip-full python3-matplotlib python-tk python3-dev qt5-q