- The 2nd prototype of ANA has been released. Check the download page here.
- ANA sponsors the ACNM 2008 workshop
Network compartments are free to internally use whatever addressing, naming, routing, networking mechanisms, protocols, packet formats, etc., they want. The objective is to enable variability and evolution by not imposing any restriction on the internal network operation of compartments. However, to support all possible and unforeseen interactions, all compartments must support a generic “compartment API” which provides the “glue” that permits to build complex network stacks and packet processing paths.
With respect to application developers, a key requirement is that the API primitives support generic arguments such that applications can use the same programming primitives to communicate with any compartment. In other words, the objective is that developers write “network-agnostic” applications that do not need to be modified to support newly developed network compartments. For example, one could write a “content browser” (similar to today’s web browsers) that takes any opaque string as user input. The browser would then find the right network compartment for handling this address or name and it would require from it a communication channel to the destination. Eventually the browser would send the data to the target FB at the destination without, at any time, having to understand the syntax of the input string.
We borrow a fundamental networking concept from the Open Systems Interconnections (OSI)  architecture which introduces the notions of user and provider layers. Basically, in OSI a provider layer N provides network services to all the N+1 layers of the architecture. For example, a network layer offers a connectivity service to all the transport layers. We embed this fundamental networking concept into the architecture via the compartment API. Basically, a user functional block requests services from a provider layer via the compartment API: because it is generic, the user-provider relationship between compartments is not fixed and network compartments are potentially combined in any arbitrary way. Note however, that we do not mandate OSI layers or a static layering as in OSI.
As a starting point towards generality, the compartment API currently offers five fundamental primitives detailed below with some simplified C-style function prototypes. Similar to Plutarch , the API follows a publish/resolve communication model in which a service is published within a certain compartment’s context. A published service then is resolved and the obtained IDP can be used to send data to the resolved service. Beside resolution, one also may lookup a service to obtain further reachability information but not instantiate an information channel to the service.
IDP p publish(IDPc, CONTEXT, SERVICE) int unpublish(IDPc, IDP published, SERVICE) IDP r resolve(IDPc, CONTEXT, SERVICE) void* lookup(IDPc, CONTEXT, SERVICE) int send(IDPr, DATA)
In the primitives, IDPc identifies the compartment handling the request. The SERVICE argument is typically what is published or looked up, while the CONTEXT argument defines some scope inside the compartment. Note that the term service is used throughout this paper to refer to any kind of resource that is resolved. This, for example, includes addresses, names, network nodes, protocol entities, files, video streams, printing services, etc.
To further describe and illustrate the compartment API we present in the next sections some simple examples of compartment communications and describe how each scenario would be implemented with the basic primitives of the API.
1) Node Local Communication Setup: Since each node is organized as a compartment, the communications inside a node are also setup via the compartment API. In particular, functional blocks publish IDPs and resolve services inside the node compartment with the same primitives used to communicate with network compartments. As a basic functionality, this allows each functional block to discover the services and network compartments available inside the node in which it is running. For example, a functional block implementing the Ethernet protocol publishes itself inside the node compartment with the following primitive:
y publish(NODE_IDP, ".", "ETHERNET")
Generally, NODE IDP is provided by the node compartment. In this example CONTEXT is defined as ”.” which restricts all operations to the local node. Upon success, the publish primitive returns the IDP 'y' (randomly generated) which is now bound to the Ethernet functional block. Now, a second functional block which wants to send data through an Ethernet interface will be able to resolve this IDP with the following request:
y resolve(NODE_IDP, ".", "ETHERNET")
This functional block (e.g., an IP stack), now uses the IDP 'y' for communication with the Ethernet functional block. A possible communication between an Ethernet and an IP functional block is shown in the next two examples.
2) Publishing an IP Address: In Fig. 6, the functional block implementing the IP stack (IP-FB) publishes its IP address inside the Ethernet compartment via the Ethernet functional block ETH-FB. This means that the IP-FB becomes reachable via the Ethernet compartment with the service name “10.1.2.3”. This publication is performed by the IP-FB by calling the primitive
z publish(y, "*", "10.1.2.3")
which, upon success, returns the IDP 'z'. Note that the generic CONTEXT “*” specifies the largest possible scope as interpreted by the compartment: for the Ethernet compartment this typically means all attached hosts on the segment and maps (inside the compartment) into the broadcast address FF:FF:FF:FF:FF:FF. For an IP compartment, the CONTEXT “*” would typically be interpreted as being the local subnet address (e.g., “10.1.2.255” for a class-C subnet). It is also possible to specify a particular CONTEXT: for example, with the Ethernet compartment, a multicast service may be published by specifying the Ethernet multicast address to be used (as shown on the following example):
m publish(y, "01:00:5e:00:00:09", "188.8.131.52")
3) Resolving an IP Address: Fig. 7 illustrates the resolve primitive. In this follow-up example, an “IP-stack” functional block inside Node N asks the Ethernet compartment (via ETH-FB) to resolve the service “10.1.2.3” in the “*” CONTEXT (i.e., the entire Ethernet segment). This is performed by calling the primitive
s resolve(e, "*", "10.1.2.3")
which, upon success, returns the IDP 's' which is used to send data to the resolved service. Inside Node N, the ETH-FB maintains some state that permits to transfer any data sent to the IDP 's' to the IDP 'z' in Node M. For Ethernet, this information includes the MAC address of the destination node plus a dynamically allocated token value used for demultiplexing packets at the destination node.
How the real resolution is performed is left to the compartment. In the case of the Ethernet compartment, a resolution request triggers the sending of a broadcast message (sent to FF:FF:FF:FF:FF:FF) containing the service name (here “10.1.2.3”) being looked up. Any Ethernet FB that has published the service in the “*” CONTEXT replies to the request with a message containing the information needed to reach the service via the corresponding compartment. For the Ethernet compartment this request-reply phase is actually similar to today’s operation of ARP (Address Resolution Protocol) but with dynamically assigned “type” values for the Ethernet header.
The lookup primitive is similar to the resolve primitive except that it does not instantiate an information channel to the service but solely returns reachability information about the service. In the case of the Ethernet compartment, a lookup may simply return a boolean answer indicating whether the service is reachable (and can be resolved) or not. The lookup primitive is actually useful for compartments that solely maintain mappings between multiple namespaces but do not forward data: this is for example the case of the Domain Name System which translates DNS names into IP addresses.