Preliminary Panda User Guide


The purpose of this document is to get you started working with Panda. It is separated into the following sections:

  1. Introduction to Panda
  2. Preliminary Panda Design
  3. Building Panda
  4. Writing Adaptors in Panda
  5. Running Panda
  6. Problems


1. Introduction to Panda (Top)

Panda (Peer Agent Negotiation and Deployment of Adapters) is a middleware support system for active networks that will allow both aware and unaware applications to benefit from the superior adaptability and performance of active networks. It will perform planning and negotiation of active network agent deployment, will adapt to failures and other major changes in network characteristics, and will handle automatic deployment of agent code to active network nodes.

The Preliminary Panda is being built on top of the ANTS active node transfer system from MIT.

2. Preliminary Panda Architecture (Top)

Overview of major Panda Components

The design contains 3 main components, the Panda Adaptation Component (the PAC), the Panda Observation Component (POC), and the Panda Interception Component (PIC).

The POC monitors and reports system and network conditions to the PAC. This data is used by the PAC and planning code to determine a plan of what adaptations to deploy.

The PIC allows a C or Java application to intercept outgoing TCP connections or UDP packets. The PIC consists of a dynamically loadable Linux kernel module and Java classes to control the actions of the kernel module.

The PAC is the heart of the Panda system. The PAC consists of an ANTS application, an ANTS protocol, and several ANTS capsule types. The PAC instructs the PIC to intercept an applications data stream, deploys adaptors in the form of ANTS capsules based on information from the POC, and sends the intercepted data in ANTS capsules over the active network towards the destination PAC.

An ANTS-style Protocol is created for each application that Panda will provide service to. The Protocol serves to identify the port number and the possible adaptations that may be applied to the applications data stream.

There are 2 different types of ANTS Capsule types used, a PandaDataCaspule and a PandaAdaptorCapsule. The PandaDataCapsule contains the payload, other related data, and planning code. It is the only Capsule type that is sent over the active network. PandaAdaptorCapsules contain the adaptor code and are only executed at an ANTS node.

Run-Time Description of Panda

The PAC, an ANTS terminology application, is started with a list of protocols describing the applications (actually port numbers) that it should intercept. The PAC then informs the PIC that it wants to intercept this list of port numbers.

When an application is started and begins to send data to one of the intercepted port numbers, the PIC re-routes the packet to the PAC. The PAC determines what application this packet came from and what Protocol it should use for the application. The application and its data stream is then given a unique SessionID by the PAC.  All subsequent messages from this application are intercepted by the PIC and assigned the same SessionID in the PAC.

The packet's payload is then encapsulated in a PandaDataCapsule that also contains the SessionID, and it is marked as a "planning" capsule if it is the first capsule for this session. If this is a planning capsule, the PAC then runs planning code that determines what adaptors should be deployed locally on this Node, and puts this information in the Node cache. The adaptors specified in the cache are then run (it doesn't matter if this was or was not a planning capsule), and the capsule is sent from this node towards the destination.

On intermediate nodes, if the capsule is marked as a planning capsule, the capsule is sent to the PAC on the node. The PAC then runs planning code that determines what adaptors should be deployed on this Node, and puts this information in the Node cache. The adaptors specified in the cache are then run, and the capsule is sent from this node towards the destination. Note that this is the same action that takes place on the originating node after encapsulation.

On intermediate nodes, if the capsule is NOT marked as planning, the capsule uses the SessionID to lookup in the Node cache what adaptors are to be run on this node. These adaptors are run, and the capsule is sent towards the destination. In this case, the capsule is not delivered to the PAC.

At the destination node, the capsule is always sent to the PAC. If it is a planning capsule, the planning code is run to determine what adaptors should be deployed on this node, and this information is put into the Node cache. The planning that occurs on the destination node is special in that it must deploy the necessary adaptors to put the payload in a form understandable by the destination application. The PAC then runs the adaptors specified in the cache. After running the adaptors, the PAC sends the payload contained in the Capsule to the destination application via the local PIC.

The planning code uses accumulated information found in the Capsule plus local information obtained from the POC. The accumulated information currently consists of a list of visited nodes along with the adaptations applied at these visited nodes. As the POC becomes more functional, the information stored in the Capsule could expand to include network and node characteristics that may affect planning. The planning code and algorithms to do planning will be modified at a later time.

3. Building Panda (Top)

Checking Out Panda from CVS

The Panda source code is controlled using CVS.  There are two modules you need to check out from the CVS repository, "Panda" and "IPcept".  To do this, make sure you have set the environment variable CVSROOT to /h/ficus-cvsroot.  To check out the source, use the CVS checkout command.

  1. cd ~/workdir        (You can use any directory)
  2. cvs checkout Panda
  3. cvs checkout IPcept

This will create two subdirectories named "Panda" and "IPcept" that contain all the source for Panda. 

Description of Directories

The IPcept directory contains the code for the Panda Interception Component, aka the PIC. The PIC code is separated from the regular Panda directory because it is shared with Conductor. The PIC consists of a Linux dynamically loadable kernel module, Java Classes used to control the PIC module and a helper shared library written in C. The IPcept subdirectories are organized as follows:

The Panda directory contains the ANTS code and Java classes that represent the core of Panda:  the PAC, POC, and the adaptor code. The Panda subdirectories are organized as follows:

A Classes/POC/ directory might be created in the future to hold source code for the POC.

Setting Up Your Environment For Panda

To build and use Panda, your environment must be set correctly.  This means having java in your PATH and correctly setting the environment variable CLASSPATH.

Update: If java fails to run, saying it can't find some system class (like java.lang.Thread), try putting the full path to the classes.zip file in your CLASSPATH. Then try setting JAVA_HOME to /usr/local/java.

To run java, /usr/local/java/bin must be in your PATH.

The CLASSPATH environment variable must contain the path to several directories that contain java classes needed to run Panda.  Because all of our Java code are in java packages that begin with FMG, we need to have a directory in our CLASSPATH that contains a subdirectory named FMG.  Then the FMG directory must contain symlinks to the actual directories that contain the java classes (IPcept/Classes and Panda/Classes).

  1. cd ~/workdir      (You can use any directory)
  2. mkdir Classes
  3. cd Classes
  4. mkdir FMG
  5. cd FMG
  6. ln -s ~/IPcept/Classes IPcept
  7. ln -s ~/Panda/Classes Panda

Now, set your CLASSPATH to contain:

By running:

setenv CLASSPATH /usr/local/java/lib/classes.zip:~/workdir/Classes:~/workdir/Panda/ants-1.2
    

in the C shell or

CLASSPATH=/usr/local/java/lib/classes.zip:~/workdir/Classes:~/workdir/Panda/ants-1.2
export CLASSPATH
    

in the Bourne shell.  

Compiling the Panda Source

You need to build the PIC, ANTS, Panda, and each application specific protocol.

Building the PIC

  1. cd ~/workdir/IPcept
  2. make    (To make the kernel module)
  3. cd lib
  4. make    (To make the shared library)
  5. make links   (To make necessary symlinks)
  6. cd ../Classes
  7. make    (To make the Java classes)

Building ANTS

  1. cd ~/workdir/Panda/ants-1.2
  2. make    (To make ANTS)

Building Panda

  1. cd ~/workdir/Panda/Classes
  2. make    (To make the PAC and base Panda Protocol)

Building Application Specific Protocols

  1. cd ~/workdir/<protocol name>   (Where <protocol name> is one of the subdirectories:  LFS21, UAstring, udpXfr)
  2. make   (To make the application specific protocol)

4. Writing Adaptors in Panda (Top)

Panda is built using the ANTS active network toolkit from MIT.  Please read the documentation provided with ANTS before you begin coding.  Be sure you are familiar with ANTS Capsules and have looked at the Capsule code for the sample applications (ping, etc). You will be creating a PandaProtocol, a PandaDataCapsule, and possibly many PandaAdaptorCapsule Classes for the application you want Panda to intercept.

Currently, we create one PandaProtocol for each application we want to run.  The purpose of the PandaProtocol is to tell ANTS what Capsule/Adaptor types you will be using and to tell Panda what IP port number it should intercept in order to receive the applications data packets.  Ideally, we would like for the protocol to be created dynamically, allowing us to choose what adaptors we want to use for the application session on-the-fly, but for now we just include in all adaptors we may wish to use in a static protocol.

PandaAdaptorCapsules are used to hold the all the code and methods related to one type of adaptation. The adapt() method is then used to run the adaptor on the payload. Adaptors in a Protocol are given unique integer identifiers.

The PandaDataCapsule holds the payload and other information needed, such as payload related data, or planning info. It is the only type of capsule that is sent over the active network. This class also maintains the mapping between adaptor classes and integer identifiers, sets up the environment/arguments for adaptors, and runs the adaptors.

Creating a New Application Specific PandaProtocol

First you need to gather some information about the application you wish to intercept and create a directory for the code.

In most client/server applications, the server port number is usually fixed while the client port number changes.  The client connects to the server listening on a well known port number and tells the server what port number the client is on.  Unfortunately, this is the exact opposite of what we want in Panda.  In the future, we will have to fix Panda to understand the application specific client/server port number negotiation.  For now, we have just modified the client to use a fixed port number.

The Protocol has two purposes:  it tells ANTS what Capsule types you will be using and tells Panda what port the client application port is listening on.  Here's a rough guideline for creating an application protocol:

  1. The class is named Proto<ident>
  2. The file is named Proto<ident>.java
  3. The class should be in a package named FMG.Panda.Protocols.<ident>
  4. Needs to include FMG.Panda.* and ants.*
  5. Is subclassed from PandaProtocol
  6. Inside the default constructor Proto<ident>() you need to call addCapsule() for each one of the capsule classes you will be using, including the protocol class.  You must always call addCapsule() for classes FMG.Panda.PandaDataCapsule and FMG.Panda.PandaAdaptorCapsule
  7. You need to create a protected function named getAppIPPort_ProtoDep() that returns the client port number (an int value).

Here's an example application specific Protocol class for application identifier LFS, named ProtoLFS:


package FMG.Panda.Protocols.LFS;	// Define the Package name

// Import the necessary classes
import FMG.Panda.*;
import ants.*;

public class ProtoLFS extends PandaProtocol {

    public static int applicationIPPort = 1450;

    // Define default constructor
    public ProtoLFS() throws Exception {
        // Always need to call these two functions before calling
        // addCapsule()
        startProtocolDefn();
        startGroupDefn();

        // Use addCapsule() to tell ANTS what Capsules you will
        // be using in your protocol
        addCapsule("FMG.Panda.PandaDataCapsule");	// Always need to include this class
        addCapsule("FMG.Panda.PandaAdaptorCapsule");	// Always need to include this class
        addCapsule("FMG.Panda.Protocols.LFS.ProtoLFS");
        addCapsule("FMG.Panda.Protocols.LFS.ProtoLFSDataCapsule");
        addCapsule("FMG.Panda.Protocols.LFS.AdaptorCapsule1");

        // Always need to call these two functions after calling
        // addCapsule()
        endGroupDefn();
        endProtocolDefn();
    }

    // This required function returns the port number of the application
    protected int getAppIPPort_ProtoDep() {
        return applicationIPPort;
    }
}

Creating the application specific PandaDataCapsule class

PandaDataCapsules are the only capsule types that are sent across the Active Network. PandaDataCapsules hold the payload from the UDP packet, any other data/information (payload and plan related data), are responsible for communication to and from the Panda Application (the PAC), and execute adaptors on the payload.

Adaptors in Panda are identified by unique integers.  PandaDataCapsule contains a method to provide a mapping between identifier number and Java class, and then run the adaptor.

In later versions of Panda, the PandaDataCapsule class may be used to correctly setup the environment/arguments to the Adaptors and also provide planning information to the Panda Application (the PAC).

Here's a rough guideline for creating an application specific PandaDataCapsule class:

  1. The class is named Proto<ident>DataCapsule   (where <ident> is the application identifier)
  2. The file is named Proto<ident>DataCapsule.java
  3. The class should be in a package named FMG.Panda.Protocols.<ident>
  4. Needs to include FMG.Panda.* and ants.*
  5. Is subclasses from PandaDataCapsule

Needs to contain 2 final private byte[] fields that are used as Capsule identifiers in ANTS:

final private static byte[] MID = findMID("FMG.Panda.Protocols.<ident>.Proto<ident>DataCapsule");
final private static byte[] PID = findPID("FMG.Panda.Protocols.<ident>.Proto<ident>DataCapsule");

Necessary methods:

protected byte[] pid() { return PID; }
This is needed by ANTS.

public int length();
public Xdr encode();
public Xdr decode();
These are used by ANTS for serialization and deserialization of the Capsule.  Make sure any additional data fields you need to keep are serialized and deserialized in these functions.

public ByteArray runAdaptorNumber(ByteArray data, int adaptorNum);
This is the function that maps adaptor integer identifiers to adaptor capsules and then runs the adaptor.  data is the payload to run the adaptor on, adaptorNum is the identifier for the adaptor.  Create an adaptor object of the correct class corresponding to the adaptor identifier, run the Adaptor using the runAdaptor() method, set the field data as the result of running the adaptor, and return data.

public Proto<ident>DataCapsule() { }
The default constructor.

public Proto<ident>DataCapsule(int destAntsAddr,
    short destAntsPort,
    int srcAntsAddr,
    short srcAntsPort,
    String destIPAddr,
    int destIPPort,
    String srcIPAddr,
    int srcIPPort,
    String SID,
    int planning,
    boolean fromPA,
    ByteArray data) {

    super(destAntsAddr, destAntsPort, srcAntsAddr, srcAntsPort,
        destIPAddr, destIPPort, srcIPAddr, srcIPPort,
        SID, planning, fromPA, data);
}
    

This is the "normal" constructor that is called.  The arguments, which correspond to fields in the base PandaDataCapsule class are as follows:

destAntsAddr
The destination ANTS address.

destAntsPort
The destination ANTS port.  This is usually the port number that the Panda Application (PAC) is listening on.

srcAntsAddr
srcAntsPort

ANTS address and port of the Source Panda Application.

destIPAddr
The destination IP address, a dotted quad as a string.  This makes it easier to used with class InetAddress

destIPPort
The destination IP port.

srcIPAddr
srcIPPort
The IP Address and Port number of the source.  Same format as the destination IP addr/port.

SID
The Session ID for capsule.

planning
1 if is this a planning packet, 0 otherwise

fromPA
True if this capsule has just come from the Panda Application (PAC).  Useful in evaluate() routine.

data
The payload.  This is the same payload that was in the UDP packet.

Here's an example source file for the application specific DataCapsule, for application identifier LFS:


package FMG.Panda.Protocols.LFS;

import FMG.Panda.*;
import java.util.*;
import ants.*;

public class ProtoLFSDataCapsule
    extends PandaDataCapsule
{
    final private static byte[] MID = findMID("FMG.Panda.Protocols.LFS.ProtoLF
SDataCapsule");
    protected byte[] mid() { return MID; }

    final private static byte[] PID = findPID("FMG.Panda.Protocols.LFS.ProtoLF
SDataCapsule");
    protected byte[] pid() { return PID; }

    public int length() {
        return super.length();
    }


    public Xdr encode() {
        return super.encode();
    }

    public Xdr decode() {
        return super.decode();
    }

    public ByteArray runAdaptorNumber(ByteArray data, int adaptorNum) {
        PandaAdaptorCapsule aCap;

        switch (adaptorNum) {
        case 0:
            aCap = new PandaAdaptorCapsule(data, theNode);	// A "null" adaptor
            break;
        case 1:
            aCap = new AdaptorCapsule1(data, theNode);
            break;
        default:
            aCap = new PandaAdaptorCapsule(data, theNode);
            break;
        }

        aCap.runAdaptor();
        data = aCap.getData();
        return data;
    }

    public ProtoLFSDataCapsule() { }

    public ProtoLFSDataCapsule(int destAntsAddr,
        short destAntsPort,
        int srcAntsAddr,
        short srcAntsPort,
        String destIPAddr,
        int destIPPort,
        String srcIPAddr,
        int srcIPPort,
        String SID,
        int planning,
        boolean fromPA,
        ByteArray data) {

        super(destAntsAddr,
            destAntsPort,
            srcAntsAddr,
            srcAntsPort,
            destIPAddr,
            destIPPort,
            srcIPAddr,
            srcIPPort,
            SID,
            planning,
            fromPA,
            data);
    }

}
    


Creating the Actual Adaptors

Panda Adaptor classes/capsules only have one purpose, to adapt the data.  Panda Adaptor objects are created for use on the Node only; they do not get sent out over the Active Network even though they are ANTS capsules.  Here's the guidelines for creating a new adaptor:

  1. The class may be named anything you want, but this name must correspond to a unique number so the application specific DataCapsule knows what adaptor class to create/use.
  2. The file is named <classname>.java
  3. The class should be in a package named FMG.Panda.Protocols.<ident>  (where <ident> is the application identifier)
  4. Is subclassed from PandaAdaptorCapsule

Needs to contain 2 final private byte[] fields that are used as Capsule identifiers in ANTS:

final private static byte[] MID = findMID("FMG.Panda.Protocols.<ident>.<class name>");
final private static byte[] PID = findPID("FMG.Panda.Protocols.<ident>.<class name>");

Necessary methods:

public ByteArray adapt()
This function is called to adapt the ByteArray field data (the payload of the UDP packet). After adapting the payload, it should set data to the new (adapted) payload and return data.

public <classname>(Node n) { super(n); }
public <classname>(ByteArray D, Node n) { super(D, n); }

The constructors for class <classname>.  D is the Data that will be adapted (the payload), n is the Node that this adaptor is running on.

Here's an example source file for adaptor class AdaptorCapsule1 with application identifier LFS:


package FMG.Panda.Protocols.LFS;

import FMG.Panda.*;
import ants.*;

public class AdaptorCapsule1
    extends PandaAdaptorCapsule
{
    final private static byte[] MID =
    findMID("FMG.Panda.Protocols.LFS.AdaptorCapsule1");
    protected byte[] mid() { return MID; }

    final private static byte[] PID =
    findPID("FMG.Panda.Protocols.LFS.AdaptorCapsule1");
    protected byte[] pid() { return PID; }

    public ByteArray adapt() {
        // Do Nothing to the Data
        return data;
    }

    public AdaptorCapsule1(Node n) { super(n); };
    public AdaptorCapsule1(ByteArray D, Node n) { super(D, n); }
}
    


Compiling your new Panda code

Unfortunately, we still have not settled on a way to build the code.  You may either call javac on all your source files, or borrow one of the Makefiles from the other protocols and adapt it for your source (preferred method for now).

Getting ready to run your new code

To run your code, you need to create 3 files, Panda.start , Panda.config , and Panda.routes.

Panda needs to run as root in order to intercept UDP messages. Because sudo sets a clean environment when running any program as root, it is difficult to call java from sudo. For this reason, the file Panda/Classes/util/run was created.  I use this script in place of calling  java when I need java to run as root using sudo.  This shell script sets the environment variables needed to run java, and then runs java with the arguments you've given it. You'll need to modify it to set the environment variable correctly for you.

Panda.config is the ANTS configuration file. Here's a sample Panda.config file that creates 3 nodes:


node 18.31.12.1 -routes Panda.routes
channel 18.31.12.1 localhost:8001 -log 127
application 18.31.12.1 FMG.Panda.PA -numAdapts 1 -adaptSeq '1' -doProxy true -protocolName LFS.ProtoLFS
manager 18.31.12.1 -gui true -log 255

node 18.31.12.2 -routes Panda.routes
channel 18.31.12.2 localhost:8005 -log 127
application 18.31.12.2 FMG.Panda.PA -numAdapts 1 -adaptSeq '2' -protocolName LFS.ProtoLFS
manager 18.31.12.2 -gui true -log 255

node 131.179.192.155 -routes Panda.routes
application 131.179.192.155 FMG.Panda.PA -numAdapts 1 -adaptSeq '1' -protocolName LFS.ProtoLFS
channel 131.179.192.155 localhost:8003
manager 131.179.192.155 -gui true -log 255

connect 18.31.12.1 18.31.12.2
connect 18.31.12.2 131.179.192.155
    


node <node address> -routes Panda.routes
node creates a new node.  <node address> is the ANTS address of the node. For Panda, we use the IP address as the node address UNLESS we are running multiple Panda nodes on the same physical node.

channel <node address> localhost:8001 -log 127
channel maps a node address to a real UDP hostname:port pair, and gives a log level. In this example, the panda node specified in <node address> will be listening on localhost:8001

application <node address> FMG.Panda.PA -numAdapts <num adapts> -adaptSeq <sequence> -doProxy true -protocolName <protocol name>
application tells ANTS what application will be running on the node with <node address> and gives the application arguments. For Panda, the application will always be FMG.Panda.PA
-numAdapts <num adapts> tells Panda that there will be <num adapt> adaptors run on this node.
-adaptSeq <sequence>, is a comma separated list of integers corresponding to the adaptor classes that should be run on this node, in order, for the protocol name. The number of adaptors in this sequence should correspond to the number you specified in the -numAdapts argument
-doProxy true tells Panda that it should intercept an application, use this on the node that is running the legacy application.
-protocolName <protocol name> gives the name of the protocol that will be run on this node. Do not include "FMG.Panda.Protocols" in this name. In the above config file, we are running LFS.ProtoLFS

manager <node address> -gui true -log 255
This tells ANTS that the node <node address> will be using a GUI and gives a logging level.

connect <node1> <node2>
This command creates a connection between ANTS node1 and ANTS node2.

Panda.routes is a file generated by the "makeroutes" program supplied in ANTS. Whenever you change your Panda.config file, you should rebuild your Panda.routes file. Do this by running on the command line:

Panda/ants-1.2/runs/makeroutes -route < Panda.config > Panda.routes
    

Panda.start is a simple shell script to start the Panda node(s). It is less useful when you are running on multiple (physical) nodes unless you create 3 different versions of it.  Here's a sample line from Panda.start:

run ants.ConfigurationManager Panda.config 18.31.12.2

This uses the run script to start a java ANTS node.  Panda.config is the configuration file, and the node you are starting has the (ANTS) address 18.31.12.2

5. Running Panda (Top)

You first need to load the kernel module, the PIC, on all machines you intend to run Panda on. do this by running:

In this directory, you can also do a make stop to stop and unload the kernel module. It might not work though, because there may be some open sockets. It still doesn't stop as easily as it should, but I'll get around to fixing this real soon :)

Now, if your code works correctly, you should do for each node running Panda:

After Panda starts up, you should see a window for the node. At this point, you can run the legacy application on one of the machines you specified -doProxy true in the Panda.config file.

If your application is outputting data, Panda should be intercepting the data, and the count of packets in the window should increase.

6. Problems (Top)

Please let me know if you have any problems running Panda or if you have any comments/questions regarding this document. My email address is on the bottom of this document.



Home | Map | History | Search

ferreria@cs.ucla.edu
Last modified: Tue Jul 20 11:00:41 PDT 1999