9 Column Aerosols
9.2 Measurement Programme
Simulations involving mobile agent or mobile code in general cannot be run using the standard NS package. An extension is required to include the necessary features. This section describes the design and implementation of such an extension.
4.3.1 Assumptions
The following simplifying assumptions are made in order to implement the mobile agent model.
1. Instead of sending the actual agent code along with data and execution stack, only a reference to the agent’s OTcl object is sent. Thus, the actual sizes of agent’s code, data and execution state are required to be set as parameters of an agent. So it is assumed that all these parameters are known.
2. It is assumed that the servers, whose services are desired, are known in advance.
3. It is also assumed that the number of bytes required for request and reply in each interaction is known.
4. The processing time for an agent (if not explicitly specified for a specific scenario) and also the time for marshalling and unmarshalling are assumed to increase linearly with the total size of the agent.
5. The marshalling factor (marshalling time per unit byte) and time required for an agent’s creation is assumed to be known.
6. The selectivity (Strasser pg. 18) of the mobile agent, defined as a factor by which the mobile agent reduces the size of the reply by remote processing, is also assumed to be known (if applicable).
7. No assumption is made about the underlying communication facilities for migrating agents. Any communication models including RPC, RMI, CORBA etc. can be utilized. But no such models are currently implemented in NS.
8. TCP is used as an underlying transport layer protocol. UDP may also be used here but the above choice is made only for the sake of performance analysis under reliable conditions.
9. As the principle aim of implementing this model is performance analysis of mobile agents, no consideration is given to the security matters in mobile agent systems. Thus, no security overhead is assumed.
10. Although implementation is based upon an entry-point migration (Brewington pg. 15) (weak migration mainly using IBM’s Aglets API ), it is assumed to be equally applicable to the study of agent systems with other types of migration using appropriate values for the model parameters. For example, while studying strong migration, one can account for the size of agent’s current execution stack, which can be otherwise considered as zero for weak migration.
4.3.2 Deciding the Inheritance Structure of the Model
In order to implement the basic behavioral model of mobile agent, the main objects required are a mobile agent itself and a context or a place where mobile
agents can execute on a given node. Here, context is responsible for creating mobile agent and also for providing each and every facility required by the agent like dispatching to other node, loading and processing the incoming agent, registering, disposing etc. It uses the existing communication facilities for mobile agent migration. Thus, a context must be implemented on top of the transport layer facilities. Just like the real world systems, NS applications are implemented on top of the transport layer agents. Any simulated application is required to implement the Application interface provided in NS. Thus the mobile agent’s context is required to implement this Application interface. Though context is implemented as an application, the mobile agent system model can be easily utilized for building real world applications on top of it.
Traffic generators Simulated applications
API API Application/
Traffic/
Exponential
Agent/UDP Agent/TCP/FullTcp
Application/FTP
Figure 4.3. Application layer in NS.
On the other side, a mobile agent object does not need to fit itself to any particular level of abstraction. It can be just a simple C++ class derived from the class TclObject. As stated before, TclObject is the root of all OTcl library objects and so all the objects that will be accessed by OTcl interpreter, are required to derive from TclObject. The methods in TclObject are responsible for creating a shadow object (i.e. corresponding C++ object) for each OTcl object. Mobile agent’s class (MAgent) also derives from the class TimerHandler in order to implement timers for various events handling.
4.3.3 Transferring Application-level data in NS
As shown in Figure 4.3 (“NS2” 1996), there are two basic types of applications in NS: traffic generators and simulated applications. Simulated applications mainly include FTP and Telnet, while traffic generators mainly include CBR and Exponential. But all these applications are “virtual” applications, i.e. they do not actually transfer their own data in the simulator. Thus, as oppose to the real world systems, there is no actual data transfer between the application and the transport agent it uses for communication. But in the mobile agent model, a sending context is required to transfer a mobile agent reference to the receiving context. So the question is how actual data can be transferred at the application level.
In order to transmit application-level data in NS, a uniform structure is provided to pass data among applications and to pass data from applications to transport agents. It has three components: a representation of a uniform application-level data unit (ADU), a common interface to pass data between
applications (class Process- base class of Application), and a mechanism to pass data between applications and transport agents.
ADU is required to pack user’s data into an array that can be then included in the user data area of the packet by NS transport agents. But as said earlier, existing NS transport agents do not support user level data. Hence either user must derive new agents for sending its own data, or some type of wrapper must be used in between application and the transport layer agent. One such wrapper used is TcpApp. TcpApp is used for sending user data over TCP. It works as follows:
Application (Context)
send_data(ADU) process_data(ADU)
send(bytes) recv(bytes)
packets Application Wrapper
(TcpApp)
Agent (FullTcp)
Figure 4.4. Transferring user level data in NS.
Using TCP agents, all the data are delivered in sequence. Thus, a TCP connection can be seen as a FIFO pipe. Further, applications are provided with
certain up-calls from the transport agents. This includes a recv() call for each packet along with the number of bytes received. TcpApp provides a buffer for application data at the sender. It also counts all the bytes received at the receiver. When receiver gets all the bytes of the current data transmission, as requested by the user, it gets the data directly from the sender. This direct communication between the applications again is made possible by using a common interface provided by class Process. TcpApp in turn can use only FullTcp or SimpleTcp. Currently it does not support asymmetric agents, i.e.
agents acting only either as a sender or a receiver
Thus, in order to transfer a mobile agent (actually only its reference) from one context to another one, a context is required to be derived from TcpApp using it as a wrapper to communicate with the transport layer agents (refer Figure 4.4). Also TcpApp requires using FullTcp as a transport agent as the only other option SimpleTcp is actually implemented as a UDP agent.
4.3.4 Design Overview
Figure 4.5 shows the complete hierarchy for class Context implemented as a child class of TcpApp that in turn derives from Application interface. Thus, the corresponding OTcl hierarchy name is “Application/TcpApp/Context”. Similarly MAgent is directly derived from TclObject and hence its corresponding OTcl name is also “MAgent”.
The following are the basic elements that have been modeled here:
• Context or Place: Context class provides the execution environment required for agent’s execution including creating any number of agents,
retracting agents from a remote site, disposing agent, registering agent and actual transferring of agent to another context. By registering agents, it maintains the list of currently executing agents in a hash table mapped with the agent’s ID. In order to transfer an agent’s reference, as discussed before, it needs to define an ADU (Application Data Unit) that derives from the class AppData. AppData is the base class for all ADUs. The class thus defined to carry agent’s reference is named as MobileAgentData.
Process
Application
Application/TcpApp
Application/TcpApp/Context TclObject
TclObject TimerHandler
MAgent
Figure 4.5. Class hierarchies for the model.
• Mobile Agent: MAgent class implements the basic functionalities of mobile agents like starting the agent after creation or arrival at a context, dispatching the agent to a remote context, disposing itself after completion of task, deactivating for a certain period of time, and cloning to make a copy of itself. It also provides certain abstract methods to be implemented by the class extending MAgent. These methods are the agent’s entry point method run(), and certain other provided for agent’s initialization and actions pertaining to certain conditions like before dispatching, after arrival, before cloning etc. There are three objects provided to listen to various events caused by agents viz. mobility, persistency and clone listeners. Their job is to listen to the corresponding agent events and invoke the matching actions.
As MAgent class contains some abstract methods, it cannot be instantiated.
To instantiate an agent object, one must extend from the MAgent class. To facilitate this extension in both C++ and OTcl, a new class named MAgentInst is created by inheriting from MAgent class. It is actually this class’s object that shadows with the OTcl class MAgent. It is used to create a default implementation of all the abstract methods in MAgent class to call the corresponding method in OTcl and thus allowing extending the MAgent class directly in OTcl. Figure 4.6 tries to demonstrate the relationship between different classes mentioned above.
Figure 4.6. Class relationship of the model.
4.3.5 C++ and OTcl linkage for the Model
NS has special infrastructure to allow extension in both C++ and OTcl, taking into consideration the factors like efficiency provided by compiled language and easy and fast configuration capabilities provided by OTcl. Most of the code in the mobile agent model has been implemented in C++ for efficiency purposes. The part requiring less frequent access and the agent configuration is done in OTcl.
Thus, we can say it is a split model between two languages. Hence, a mechanism is required to link the C++ code to that of interpreter and vice versa.
Each C++ object is required to link to the corresponding OTcl object. For example as shown in Figure 4.7 C++ Context object’s reference is linked to the class Application/TcpApp/Context object’s reference (simply a name) in OTcl.
This linking is done by extending the classes like TclObject and TclClass. The C++ object whose linking with OTcl object is desired must inherit either directly or
otcl class
Figure 4.7. C++ and OTcl linkage for the model.
indirectly from TclObject. Also for each such object’s class, a static class extending TclClass must be defined. This class performs two functions: (1) construct the interpreted OTcl class hierarchy to mirror the compiled class hierarchy, using the string pass to the constructor of TclClass
(“Application/TcpApp/Context” here) and (2) instantiate new corresponding TclObject. The following code shows how this is done in a static class ContextClass of this model.
/* ContextClass that is responsible for creating a shadow compiled object when the corresponding interpreted object is instantiated. */
static class ContextClass : public TclClass { public:
ContextClass() : TclClass("Application/TcpApp/Context") {
} // Passing the corresponding OTcl hierarchy in string form to TclClass TclObject* create(int argc, const char*const* argv) {
// called when the corresponding OTcl object is instantiated to // create a new C++ object
return (new Context ( recv_tcp, send_tcp, argv[6]) );
}
} class_context;
This static class is created at the startup of NS and hence is always available whenever new objects are required to be instantiated. For example a user can instantiate new context in the simulation script as follows:
set context_ [new Application/TcpApp/Context arg1 arg2 arg3]
# arg2 and arg3 are optional
Also in OTcl code the following constructor is defined.
Application/TcpApp/Context init args { eval $self next $args
# other initializations }
Here the interpreter as part of instantiating a new Context object performs the sequence of actions. Following is a brief overview.
• First step is to obtain a reference handle for the new object from the TclObject name space, which is acting as name for the object.
• Next is to execute the above constructor for the new object. All such TclObjects are required to call their super classes in the first line as done here. This results finally in a call to TclObject constructor at the top, which is responsible for setting up the shadow object and other bindings.
• At this time the C++ create() method shown above in static ContextClass is called and instantiates the C++ object.
So this is how to bind C++ and OTcl objects. Sometimes it may also require binding different variables along with the objects; i.e. the same variable may require access from both C++ and OTcl. This can be done by establishing a bi-directional binding such that both of them reads and accesses the same value for a variable and change in one of them results in the corresponding change in other one. This binding is established by some special methods in TclObject and is required to be done in C++ constructor only. The following are some examples showing how this binding is done for some of the model parameters that can be set in OTcl .
bind("id_", &id_);
/* establishing binding between C++ integer variable ‘id_’ and OTcl
variable ‘id_’ */
bind("selectivity_", &selectivity);
/* establishing binding between C++ double variable and OTcl variable */
It is not compulsory to have the same name for both bounded variables but this helps in better understanding as they represents the same value. This binding can also be done for bandwidth and time valued variables defined in NS.
The last important matter for OTcl and C++ linkage is support for calling C++
procedures from OTcl and that for calling OTcl procedures from C++. The model uses both the above types of calls. For every TclObject that is created, NS establishes the instance procedure cmd{} as a hook to the executing methods through the compiled shadow object. The procedure cmd{} invokes the method command() of the shadow object automatically, passing the arguments to cmd{}
as an argument vector to the command() method. The user can invoke the cmd{}
method explicitly specifying the desired operation as the first argument, but more generally it is invoked implicitly, as if there is an instance procedure of the same name as the desired operation. Thus, for allowing calls from OTcl to C++, it is required to implement the command method of TclObject and then to process its arguments to understand and serve the call. The following example shows how this can be done for some of the methods provided to interpreter in MAgent class.
int MAgent::command (int argc, char const *const *argv ) {
Tcl& tcl = Tcl::instance(); // getting interpreter instance If ( strcmp ( argv[1], "context")==0) {
// if the name of the method invoked in OTcl is “context”
tcl.resultf("%s", getContext()->name());
// pass the context’s name as a result return TCL_OK; // call is handled OK }
if(strcmp ( argv[1], "dispatch")==0) {
dispatch(); // makes the corresponding call to C++ method return TCL_OK;
}
return ( TclObject::command (argc, argv ) );
/* If no command matches then pass the arguments to the parent command() method. Thus maintaining proper inheritance. */
}
There are several notable features here. The first line inside the method gets the instance of the OTcl interpreter as contained by Tcl class. This instance is required for invoking any methods in OTcl and also for passing down the results of the method invocation in between OTcl and C++. For example note the use of function tcl.resultf() in the above method. It passes the invocation result back to interpreter. Similarly results from any OTcl method invoked from inside C++ code can be obtained using a call to result() without any arguments and such invocation can be done as follows:
tcl.evalf("%s onCreation", name());
The above method calls the methods onCreation of the object represented by name() which the mobile agent’s name here.
Although complex, it is very important to understand the linkage between C++ and OTcl provided by NS because efficient extension of NS needs proper integration of both of them.
4.3.6 Mobile Agent Model Parameters
The mobile agent model is provided with enough parameters to enable them reflect the real world’s agent’s behavior. Table 4.1 shows some of the important parameters (“IBM” pg. 11) associated with a mobile agent.
Table 4.1. Parameters of a Mobile Agent
Id_
Unique ID or name given to a mobile agent. This ID is unique among all the mobile agent objects currently existing in the simulation environment.
code_size_
data_size_
Represents the size of the code and data of a mobile agent respectively (in bytes).
status_size
Represents the size of the status stack of the agent during migration. This will be required only for strong migration, as agents following weak migration do not take the current execution stack with them (in bytes).
Table 4.1. Parameters of a Mobile Agent, continued
Size_ Total size of the agent migrating from one context to another (in bytes).
selectivity_ Factor by which the mobile agent reduces the size of the reply by remote processing
State_ Current state of the agent i.e. whether it is IDLE, ACTIVE, MOBILE or TERMINATING etc.
Node_ Name of the current node of execution homenode_ Name of the originating node
context_ A reference of the current context in which agent is executing
m_factor_ Marshalling and unmarshalling factor defined as time required for marshalling the unit byte of data.
create_delay_ Agent’s creation time
process_delay_ Agent’s processing time. It is assumed to be linearly proportional to the agent’s size.
launch_delay_ The time taken by the agent while migrating to a destination node for packing and unpacking its data, state and code. It is in option to parameter m_factor_
and should not be set if m_factor_ is used.
The only parameters associated with a context (“IBM” pg. 11) are shown in Table 4.2.
Table 4.2. Parameters of a Context node_ Name of the node on which the context exists.
enable_ Flag use to set whether the context is enable or disable.
agent_list_
Reference to a hash table use to store references of all the mobile agents currently executing in the context. The hash table maps an ADU (MobileAgentData) object to the agent’s ID.
4.3.5 Mobile Agent Methods
The C++ class MAgent models the basic functionalities of a mobile agent like its starting, dispatching, cloning, deactivation, etc. Table 4.3 shows the methods (again prototype used here is inspired from IBM Aglets API) it implements and that should not be over-ridden by the derived class:
Table 4.3. Methods Implemented in MAgent Class
void dispatch() Allows an agent to dispatch itself to the next destination. The destination is taken from the agent’s inventory list.
void dispatch(const char* ) Overloaded method to allow agent’s dispatch to a particular context destination. It can be used when inventory list is not given to the agent.
void deactivate( long ) In real world the mobile agent is stored for that time on permanent storage. But here no actual storage is done. Agent just sleeps for the given duration to simulate its deactivation.
void dispose() It just deletes the current agent object and also makes sure that it is removed from the agent’s list maintained by the context.
MAgent* clone() Creates an exact copy of itself including the copy all the data members.
bool is_active() Checks if the agent is currently in ACTIVE
bool is_active() Checks if the agent is currently in ACTIVE