Some research has been conducted towards enabling applications to specify the protocol stacks required for transmitting or receiving data. However, the effort has been primarily targeted towards manipulating protocol stacks at the end-systems only. The x-kernel and Horus projects are examples of this research.
Active networking offers a different paradigm that enables programming intermediate nodes in the network. We define a network to be active if it allows applications to inject customized programs into the network to modify the behavior of the network nodes. This allows applications to customize the network processing and adapt it to the application's immediate requirements. This enables new protocols and new services to be introduced into the network without the need for network-wide standardization.
To understand the strengths and limitations of active networking, we developed Magician, a toolkit for creating a prototype active network. In an active network, program code and data is placed inside specialized packets called SmartPackets. The nodes of an active network are called active nodes and they are programmable in the sense that when a SmartPacket reaches an active node, the code inside the SmartPacket is extracted and executed. Depending on the nature of the code inside the SmartPacket, the SmartPacket either modifies the behavior of the active node or transforms the data it is carrying. Magician provides the platform on which active nodes can run, and the tools and interfaces for creating new SmartPackets and deploying new services and protocols in the active network.
Active networking offers a technology where applications can inject new protocols into the network for the network to execute on behalf of the application. New protocols can be injected into the network by embedding the protocol code inside the Smartpackets. As mentioned earlier, the nodes of the network are programmable entities and the code is executed at these nodes to implement new services or protocols. This raises important issues about the safety and security of the active nodes. There have to be mechanisms to prevent application programs from intentionally or unintentionally compromising the integrity of the internal data structures at the active nodes or those of the other SmartPackets executing at the node. Current network node architectures are overly restrictive and hence cannot be used to model an active node.
The structure of the SmartPackets needs to be studied as well. As discussed above, SmartPackets have to be able to carry their resource requirements. To create secure, survivable networks, active nodes should be able to authenticate the sender of the SmartPacket and authorize the access privileges given to the SmartPacket. All this information has to be embedded in the SmartPacket. It is also necessary to investigate architectural models that can provide a safe, sandboxed programmable platform for execution of SmartPackets. Since application code is allowed to create its own data structures and implement its own mechanisms, there is a need to limit the memory and processing requirements of the SmartPackets to prevent runaway execution or memory hogging. Active nodes have to interact with the SmartPackets to learn about their resource requirements and in turn the SmartPackets have to know about the availability of resources at the active node.
The following sections describe the architecture
of the active nodes along with the structure of the SmartPackets and the
operational details presented as FAQs. If you are interested in creating
an active network without reading about the concepts, proceed directly
to the Setup and Configuration document.
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.
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 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 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.
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.
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:
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.
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 Four11Stub
class.
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 KU_SmartPacket_V2
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 KU_SmartPacket_V2.
The functionality of the SmartPacket is described by overriding the exec()
method of the KU_SmartPacket_V2
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 KU_SmartPacket_V2
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 KU_SmartPacket_V2
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 KU_SmartPacket_V2
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.