The two principal
components of an active network are the active nodes and the
SmartPackets. The prototype active network, whose topology is
shown in Figure 1, is a collection of individual active nodes and
a single Information Server (see Four11 FAQ) each
running on a separate Java Virtual Machine (JVM). Active nodes
exchange SmartPackets by encapsulating them inside UDP packets
and sending them on UDP ports 3322-3325 of the host on which a
neighboring active node is running. The Information Server
maintains the configuration of the network. At startup, nodes in
the active network contact the Information Server to determine
adjacent nodes. This information is useful to provide a basis for
developing the infrastructure necessary for routing SmartPackets
in the active network. We provide a brief overview of the
structure of a SmartPacket and the role of active nodes in the
active network before describing the architecture of an active
node in detail.
Magician is implemented in JavaTM.The Java Virtual Machine environment supports machine-independent programs and the language is quickly becoming a standard for object-oriented programs that can be compiled into bytecodes. We opted to implement the system using version 1.1 of the Java Development Kit (JDK) for two principal reasons:
Since SmartPackets are executable entities, their state has to be preserved when they are transported from one active node to the next. Object serialization is one technique for preserving and transporting state. The state of an executing object is written out as a byte array in a particular format. The byte array is then transported across the network to the neighboring active node where the bytes in the array are used to re-create the SmartPacket. There is an added advantage in using object serialization. Since Java is being becoming increasingly popular in the active networking community, we expect most active nodes to support object serialization. This permits widespread integration of the different active network architectures.
In an active network, data packets are information entities. These entities, which we call SmartPackets, contain a destination address, user data, and methods that can be executed locally at any node in the active network. Since architectures like the x-kernel and Horus allow us to compose complex protocol stacks from single-function protocols, we can think of SmartPackets as carrying customized protocols that are fitted in with protocol modules at the network nodes.
The code in the SmartPacket can be in any executable format and it is executed at the node if the node has the correct processing environment. In our implementation, the code of the SmartPacket is actually a Java class that describes the methods that act on the user data. Each SmartPacket has a 128-bit type identifier, which is used to identify the protocol that is carried by the SmartPacket. The type identifier is a MD-5 message digest of the structure of the SmartPacket.
The idea is that any
composer of a SmartPacket (user, application, router etc.)
wanting to define a new type sends the SmartPacket definition to
a local Type Authority (currently built into the kernel at the
host node). This Type Authority authenticates the composer,
checks the structure of the SmartPacket and converts the
SmartPacket definition to canonical form. The canonical form is
then hashed (using a standard hash algorithm) into a 128-bit
number that is returned as the type identifier for the
SmartPacket. This prevents spoofing because the signature is a
one-way function and the contents of the packet can be verified
against the signature.
The overall structure of the SmartPacket conforms to the Active Network Encapsulation Protocol (ANEP). ANEP was created to enable members of the Active Networking community to implement their own execution environments at all member sites and still be able to interchange SmartPackets. The ANEP structure (Figure 2) consists of a fixed header that describes, among other things, the environment in which this SmartPacket executes, and a series of optional type/length/value (TLV) tuples. Some of the TLVs defined in the ANEP proposal are source definition TLV, destination definition TLV and authentication TLV.
Members are free to add their own TLVs to the overall structure except that they will not processed at nodes which do not understand them. We defined a class definition TLV to carry the Java class definition of the user code. We also defined an object definition TLV to carry the serialized object and a Type definition TLV that carries the type identifier of the SmartPacket.
Active nodes perform the functions of receiving, scheduling, executing, monitoring and forwarding SmartPackets. When a SmartPacket arrives at an active node, the type identifier and the user-defined code inside the SmartPacket is extracted. The type identifier is used to de-multiplex the SmartPacket to its correct processing environment. The SmartPacket is then scheduled for execution. A separate environment is required for each invocation to prevent undesirable interactions and malicious access to node resources.
Active nodes export a set of resources
and primitives that can be used by the user programs contained
inside SmartPackets. This not only provides a consistent view of
the network but also enforces constraints on the actions that can
be performed by user code. Thus an active node enforces a time
limit on the execution of SmartPackets to prevent runaway user
programs. It also imposes a limit on the total memory that can be
requested by a SmartPacket. In terms of primitives, user code has
restricted access to certain internal information such as the
routing tables, buffer space information and available link
bandwidth on the node's interfaces. The user can utilize this
information to develop application specific strategies to combat
congestion or implement a new routing policy for its packets.
The model of an active
node is shown in Figure 3. An active node is made up of (possibly)
multiple processing environments such as a PLAN execution
environment or an ANTS environment. Each environment is
controlled by its node manager. When an active node boots up, it
starts a set of port managers, a demultiplexer, and the node
managers of all the environments that the active node supports.
There is one Port Manager per UDP port that the active node
listens to and on which the active node communicates with other
nodes. The list of ports that the active node listens to is
obtained from the Information Server (see Four11 server FAQ) at boot time. Incoming SmartPackets are queued
at the Demultiplexer (class Demultiplexer).
The Demultiplexer verifies that the packet conforms to ANEP
standard and then attempts to demultiplex the packet to its
correct processing environment based on the environment
identifier field in the header. This is accomplished by using the
environment identifier to index into a table to find the Node
Manager for the environment. The byte stream constituting the
packet is then handed over the environment's node manager.
In this approach, the Node Manager starts other managers such as the resource manager (class ResourceMgr), the routing manager (class RoutingMgr), the network event reporting manager (class NetLoggerEventManager) and the port interface manager (class PortInterface). The resource manager is involved in the management of node resources including scheduling and is discussed in the next section. The routing manager provides the interface for installing routing protocols and also provides a default routing mechanism for those SmartPackets that do not implement their own. More details about the routing manager are discussed later.
The port interface manager controls the assembly and disassembly of SmartPackets and their transmission and reception over the wire. The port interface manager receives a SmartPacket as a byte stream. The ANEP header is peeled off first. The TypeID TLV describes the type of the SmartPacket. If the node is receiving a packet of that type for the first time, a new SmartPacket loader is created (class SmartPacketLoader). The SmartPacket loader extends the normal Java Virtual Machine class loader by allowing new classes to be loaded from packets received over the network. The SmartPacket loader is then assigned to that type and is used whenever packets of that type are received or need to be transmitted. This also presents a separate environment for each type so that there are no name conflicts between SmartPackets of different types. Name conflicts between packets of same types are treated as errors.
To construct an incoming SmartPacket, the SmartPacket loader reads the bytecodes representing the class definition and the serialized object. After reading the SmartPacket, the classes, if any, in the SmartPacket are loaded and verified by the SmartPacket loader. The serialized object is de-serialized and checked for the presence of resource information. This resource information includes resource requirements like maximum processing time, which are passed to the Resource Manager along with the de-serialized object for processing.
The port interface manager reverses the process when transmitting SmartPackets. When it receives the SmartPacket object and information about its next hop, the object is serialized and placed in the Object Definition TLV, the ANEP header and other appropriate TLVs are added and the byte stream is transmitted on the appropriate link.
Serialization of a Java object is an expensive operation. Therefore, when a SmartPacket is received a hash is computed on the extracted data object and the object is cached. This hash is used when the same SmartPacket is ready for forwarding to determine if the entire object needs to be re-serialized. If nothing in the object has changed, simply re-sending the original cached object can save time.
When a SmartPacket arrives at an active node, the Node Manager verifies, loads, and defines the embedded class to the execution environment as described earlier. The Node Manager then forwards the de-serialized code object to the Resource Manager for execution. The Resource Manager provides an interface to resources at the node. The code in the SmartPackets is run in a thread. All requests for resources are made by the thread on behalf of the code. This is similar to the path abstraction used in the Scout operating system. Having a single thread per SmartPacket simplifies resource management because it is easy to track the resources allocated for a given thread.
Most SmartPackets arriving at an Active Node do not require sophisticated resource models. Some of the basic resources are CPU cycles, memory and I/O bandwidth. This list can be extended by including storage in which SmartPacket can leave small state at a node after its execution environment expires.
During its execution, a SmartPacket may have to create objects which need to be stored in the local memory. The active node must limit the size of storage used by a SmartPacket and the lifetime of the storage. It is not always possible to perform such low level monitoring without incurring a serious overhead. Therefore, we have not imposed any limitations at this time.
Since the resources in an active node are shared by different SmartPackets, the Resource Management entity must ensure safe resource assignment to SmartPackets. Firstly, the node must maintain its state integrity by limiting the resources to which SmartPackets have access. Secondly, the node must provide safe sharing of resources between different SmartPackets.
Access to resources is limited by imposing static maximum allocation of each resource. In this implementation, the Active Node Manager imposes static limits on some of the resources. The resources are:
At startup, the Resource Manager starts a Scheduler (class Scheduler) for scheduling SmartPacket threads and a Resource Monitor (class ResourceMonitor) that keeps track of per thread resource consumption. Resource information (such as CPU and memory requirements), which is extracted from the incoming SmartPacket, is checked against the static limits imposed by the Node Manager. If the resource requirements are more than the maximum allowed, then an exception is raised and the SmartPacket is rejected. Otherwise, a new thread is allocated to run the code in the SmartPacket and it is passed to the scheduler. As mentioned earlier, the scheduler uses feedback scheduling with dynamic priority to schedule the threads. To ensure timely execution, the scheduler allows only a fixed number of threads to start execution in any given interval of time. The Scheduler also runs periodically to revoke threads that have finished their execution time, or to lower the priority of a long running thread, or to schedule new threads.
The Resource Monitor runs as a separate thread and monitors the activities of the SmartPackets at the node. It periodically checks the current level of resource utilization for each thread. Any threads that have exceeded their pre-stated resource requirements are stopped immediately and the associated SmartPackets are discarded.
In traditional networks, packets cannot exchange information with each other as they pass through the network. However, in our implementation, we allow SmartPackets to leave information in the form of data at the nodes they traverse. The cache in which this information is stored is called as Small State. A variety of information can be stored as Small State. For example, a SmartPacket may leave behind the name of the next hop it is traversing. Trailing SmartPackets can potentially use this information. The interface to manipulate small state is currently provided directly by the Node Manager. Details about how to use the interface are described in the annotation for the class ActiveNodeManager. Note: This interface will likely be rolled into the KUSmartPacketV2 class interface in the next version. Users are cautioned to use the current interface with discretion.
The Routing Manager (class RoutingMgr) maintains the interfaces for various routing protocols to be implemented. The default routing protocol that is installed at all active nodes is the RIP routing protocol (class RIPRouting). The RIP routing protocol creates and maintains its own routing tables and provides the interface for manipulating these tables. The routing table is a simple vector of 4-tuples that describes other active nodes in the network and how to get there. But instead of sending routing table updates as data, the active routing protocol sends SmartPackets that carry code to modify, add or delete table entries at the destination. Figure 4 shows the idea of our routing protocol where the updates are sent as SmartPackets. The routing protocol sends these SmartPackets after specified intervals of time (say, every 30 seconds).
Users can install their own routing
protocol for their SmartPackets. To do so, they have to install
it at the node by using the interface provided by the RoutingMgr
class. Next the GextNextHop() method of the base
SmartPacket class (class KUSmartPacketV2)
must be overridden to return the name of the active node that
serves as the next hop towards the destination.
What is Four11?
The Four11 server (class Four11) is an
information service that maintains information about named,
virtual active networks. The idea is that the physical network of
active nodes can be overlaid by a virtual network of nodes. Thus
a physical active network can contain multiple virtual active
networks (VAN). Information about each VAN is maintained by the
Four11 server. Any active node can query the Four11 server
through a specific API to obtain information about a VAN or its
constituent nodes. Information such as the names of the active
nodes in a VAN, the physical nodes on which they reside, the
interface addresses, their neighbors in the VAN can be easily
determined.
How is the network configuration specified?
The topology of the VAN and its member
active nodes are described as lists attribute value pairs. Each
pair is of the format attribute: value. An attribute must
be a single name. The value can either be a name by itself or a
list. The list can itself have sublists. Attribute-value pairs of
all member nodes of a VAN are grouped into a list. It is thus
possible to describe multiple VANs in a single configuration file.
The configuration file is located in the magician/Four11
directory. It is possible to describe any attribute of the active
node using this method. New attributes can be added at any time.
The only restriction is that the name of the attribute must not
match the name of a value.
What is the ports attribute?
The ports attribute has as its value a list
that describes the UDP ports on which the member active node
receives SmartPackets. The port numbers given in this list must
match the port numbers listed in the nbors entry of the
active nodes that are neighbors to this node.
What is the gateway attribute?
The gateway attribute is used to
describe the active node(s) that form the gateways of the VAN.
The default behavior of the active nodes is that if a destination
address does not resolve to a valid VAN address, then the
SmartPacket is shipped to the gateway node. It is the
responsibility of the user to provide the logic for dealing with
the packet once it reaches the gateway node.
How are neighbor interfaces specified?
Since a physical active network can have
multiple VANs, the neighbors of each member node have to be
explicitly described. Neighbors are described using the nbors
attribute. The value of this attribute is a list of lists. Each
sublist describes a neighboring node. The description includes:
the virtual name of the neighboring node, its interface address,
the UDP port number on which SmartPackets must be sent and the
bandwidth of the link connecting the neighbors. If the neighbor
is more than 1 hop away, the bandwidth value is the minimum of
the link bandwidth of all the hops.
How do nodes interact with Four11 server?
Active nodes interact with the Four11
server using freeform lisp-like messages. Each message must match
the format of the attribute-value pair's description in the
configuration file. Only the first match is returned. The
interface for sending the messages is implemented by the methods
described in the Four11Stubclass.
How to start up an Active node?
Active nodes can either act as hosts (i.e.
they inject SmartPackets into the network) or they can act as
intermediate nodes (i.e. they process and forward SmartPackets).
While the underlying architecture is the same in both cases, the
startup interfaces are different. We have provided a generic
command-line interface for injecting any user SmartPacket. If the
interface is insufficient, the user can write his/her own
interface. See Starting the Network section in the Setup and Configuration document for exact details on how to start
active nodes/hosts.
How to specify the topology of an active network?
The topology of the network is specified
giving a configuration file to the Four11 server. An overview of
the Four11 server and its working are described in the Four11 FAQ. Details of the layout of the configuration file
are available in the Four11 Server and Network Setup section in the Setup and Configuration document.
How is a SmartPacket defined?
The KUSmartPacketV2
class implements the definition of the SmartPacket. It implements
the interface between the user code and the active node kernel.
Its public methods expose the functionality of the kernel that is
available to the user. The type of the SmartPacket is given by a
128-bit type identifier that is automatically generated when the
SmartPacket is created. This type identifier is used to identify
the packet in the network and to protect its integrity and the
integrity of other packets at the node. Forcing the user to
interact with the node only through the interface provided by the
SmartPacket's methods ensures safety of the node's resources.
How does an user create a new, simple SmartPacket?
The user creates his own SmartPacket
definition by extending the class KUSmartPacketV2.
The functionality of the SmartPacket is described by overriding
the exec() method of the KUSmartPacketV2
class. Using this interface enables the user to use the default
routing, unguaranteed delivery characteristics. See the SmartPing class
for an example.
For guaranteed delivery, extend the ReliableCommFW
class and override its exec() method for implementing user
functionality. The ReliableCommFW
class provides a framework that uses a simple Send and Wait for
Ack protocol (class StopAndWaitAck)
for reliable delivery and RIP routing protocol for routing. See
the SmartAckPing
class for reference.
If the user wishes to create more complex
underlying frameworks, he must override the build() method
of the KUSmartPacketV2
class and implement the framework there.
How is a SmartPacket injected into the network?
A Smartpacket is injected into the network
in one of two ways. The user creates his own SmartPacket
definition by extending the class KUSmartPacketV2
as described earlier. If the logic described in the exec()
method does not terminate the execution of the SmartPacket (i.e.
call halt() etc.) and the destination of the packet has
been set by setting the instance variable Destination_Address
then the default execution path takes over after the code in the exec()
method is executed and the SmartPacket is automatically routed to
its destination.
It is possible to create a new SmartPacket
belonging to the group of the parent SmartPacket. In this case,
the new SmartPacket can be injected into the network by calling
the SendSmartPacket() method of the newly created
SmartPacket.
How to create new, complex SmartPackets that are part of a
group?
In most complex applications, a single
SmartPacket cannot provide all the functionality. In this case,
one needs to use many classes of SmartPackets, each implementing
a piece of the functionality but are part of the same application
framework. By default, when a user creates a new Smartpacket,
it's type is derived by generating a cryptic hash of its
structure. So if there are multiple Smartpackets that a part of
the same application, then each SmartPacket will get a unique
type. The problem with this is that these SmartPackets will not
be able to interact with each other in the network because they
have different types. (Actually they can but it will be in a
unsafe manner because they have to use insecure global small
state). One way to handle this is to create a base class that
extends the KUSmartPacketV2
class or the ReliableCommFW
class or whichever new framework class that the user has created.
The base class then defines all the application SmartPackets as transient
private members of the class. Override the writeObject() method
in the base class and call the describeComponents() method
to describe the members to the system. This enables all the
SmartPackets belonging to the application to have the same type.
Send comments to Amit Kulkarni