1. Introduction This document describes the high-level software architecture of the Ouroboros prototype, an implementation of the Recursive InterNetwork Architecture (RINA). The high-level architecture described is for an implementation in user-space of an Operating System. It identifies the different software components and delineates their interactions and interfaces. The main focus of Ouroboros is portability, to allow the prototype to be deployed on different platforms and in widely varying environments. This document will assume the reader is familiar with RINA terminology. Please see the reference model for a more in-depth description of RINA. 2. The Ouroboros Framework The framework consists of a library, that implements the Recursive InterNetwork Architecture. Applications can make use of the library for networking. This is shown in Figure 1. The library offers an API to applications so they can make use of the functionality. Apart from the library, 2 types of daemon are provided: - The IPC Resource Manager Daemon, responsible for instantiating new IPC Processes, destroying them etc. It is the local management system in the processing system that handles IPC requests. - IPC Process Daemon(s), a daemon that is the instantiation of an IPC Process on the processing system. The library can run the daemons as threads instead of processes if needed, for instance when it is deployed on Android, iOS, as a web app, ... Multithreading will be supported, so that the daemons can spawn as many threads as needed for them to function correctly. The high-level architecture is devised in such a way that it tries to minimize the multitasking switches. +-------------------------+ +-------------------------------+ | Applications | | Shell scripts, config files, | | | | Python scripts, ... | +-------------------------+ +-------------------------------+ | Function calls | Function calls v v +-------------------------------------------------------------------+ | Ouroboros Library | +-------------------------------------------------------------------+ Function calls ^ | Sockets | | Function calls ^ | Sockets | v | | | v +-------------------------+ | | +-------------------------+ | IPC Process Daemon | | | | IPC Resource Manager | | | | | | Daemon | +-------------------------+ | | +-------------------------+ Function calls | | Sockets | v +-------------------------+ | DIF Allocator | | Daemon | +-------------------------+ Figure 1: Ouroboros library 3. Software components convention A component in the rest of this document adheres to the conventions described in the next paragraph. The aim of this section is to remove unnecessary detail from other sections and also to provide a unified convention for all the different components. Exceptions to these rules are allowed, if explicitly indicated. typedef uint32_t module_id_t The module_id_t represents a generic identifier mapped to an integer. As a return value, module_id_t should be interpreted as follows: - value >= 0 Represents a positive answer. The value is opaque for the callee while it has an internal meaning for the caller. The caller uses the id for requesting services (operations) to the caller, the callee may use the id for lookups into its internal data structures. - value < 0: Represents an error condition To further clarify , each component has the following lifecycle: a. Creation: The caller asks for a creation of a new instance of the component. The callee returns a generic identifier b. Operation(s): The caller asks for an operation. The identifier given during creation is always passed along as input parameter. If the operation was successful, zero is returned. In case of an error, the component returns a negative value. The negative value can be passed to ouroboros_strerror to get a human readable version of the error. The error codes are library global, in the case that the library gets migrated in other libraries, they should coincide with errno. c. Destruction: The caller explicitly asks the callee to release all resources related to the component created in step a). The identifier is passed along as input parameter to identify the correct instance. 4. Ouroboros Libraries The Ouroboros library is internally split into different smaller libraries. They are the following: - libouroboros-dev: allows applications to allocate flows to other applications, read/write to these flows, deallocate them and to register and unregister themselves in DIFs. - libouroboros-cdap: this library implements the Common Distributed Application Protocol, RINA’s application protocol. - libouroboros-irm: this library exposes the IRM API to allow network administrators to build their own network. - libouroboros-ipcp: this library allows the IRM to create, destroy, configure IPC Processes. - libouroboros-da: Allows the IRM to resolve a DAF name to a DAP member and how to reach it through an N-1 DIF.. - libouroboros-common: contains the files that are shared by all other libraries. An example is the file with error codes described in the previous section - libouroboros-utils: contains all the other files not contained in the other libraries. Examples are the implementations of the data structures described in the previous section When any of the operations is called, the caller is blocked until it the operation has been executed. Since some operations may involve sending messages to other processes, proper timeouts will be enforced on the operations to avoid blocking processes endlessly. * libouroboros-common * This library provides the definitions shared between all other libraries. Other framework components such as the IRM and IPCP daemons may also use this library and common functionalities between these daemons may also be contained within this library. * libouroboros-dev * This library provides the RINA IPC API to applications. This is the native RINA IPC API that allows application processes to register/unregister themselves with DIFs, allocate flows with a certain Quality of Service and read/write to them and deallocate them when they are no longer necessary. In the case of a server, one can first request all the available DIFs in the processing system. Next, one would register the Application Process in selected DIFs. Wildcarding is allowed, for instance * would mean any DIF, home.* all home DIFs etc. Upon registration a file descriptor is returned. This file descriptor is used for incoming flows, upon calling flow_accept with this file descriptor the name of the requesting application is provided together with a new file descriptor in case of a new flow. The server can then choose to accept or deny this new flow by calling flow_alloc_resp. If the flow is accepted, the file descriptor can then be read from and written to with flow_read and flow_write. To deallocate the flow, flow_dealloc can be called. In the case of a client, one can first request all the available QoS cubes that are available for communicating with a server. Optionally, one can pass a minimum QoS that is required for the flow. With this QoS, flow_alloc can be called to allocate flow. One can also just provide a minimum QoS in the flow_alloc call and just accept what the network gives you. A file descriptor is provided with which one should call flow_alloc_res. If this operation returns a positive value, the flow is accepted and one can call flow_read and flow_write. To deallocate the flow, flow_dealloc can be called. * libouroboros-cdap * This library provides the Common Distributed Application Protocol (CDAP) and Common Application Connection Establishment Phase (CACEP). CDAP is RINA’s stateless application protocol that allows two applications to communicate by using atomic operations: create, delete, start, stop, write, read. CACEP is RINA’s authentication protocol used when setting up communication between two Application Entities (AEs). CACEP/CDAP will have to agree on an abstract syntax (protocol version) and a specific encoding to use (concrete syntax). The library allows for new CDAP instances to be created by passing the flow it can use and a structure with callback operations. From then on, the flow can only be written and read from by the CDAP instance. To send CDAP messages, once can call any of the operations by passing the newly created instance together with the appropriate parameters. Upon receipt of a reply to the message sent, the corresponding callback operation is called. * libouroboros-irm * The IPC Resource Manager allows a network administrator to setup a RINA network. The IRM exposes an API so that commands can be given from a config file reader, scripts or even a full blown DMS. It allows the creation and destruction of IPCPs, it allows to bootstrap or enroll IPCPs, and to register and unregister IPCPs in certain DIFs and to query their RIB. It is also possible to request all the IPCPs currently in the processing system as well as all the possible IPCP types. * libouroboros-ipcp * The IRM can instantiate, destroy, configure IPC Processes. A new IPC Process is created by specifying a name and a type (normal IPCP, shim IPCP). If it is the first IPCP in the DIF, it can be bootstrapped by providing the required DIF info. If it is not the first IPCP in the DIF, it has to enroll with an existing member by calling ipcp_enroll. After the new IPCP is configured in one of the two described ways, it can be registered and unregistered with the required N-1 DIFs. Its RIB can also be queried. * libouroboros-da * The DIF allocator allows to resolve a DAF to an distributed application process and find a DIF through which it is reachable, or if a DIF is not yet available to instantiate a new DIF. In the first phase of the implementation only the first case will be supported. In the case of a DIF, for enrollment this means that an existing member can be resolved by providing a DIF name and that N-1 DIFs can be given through which the existing member is reachable. * libouroboros-utils * This library contains all the other functionalities not contained in the other libraries. This includes implementations of data structures such as lists, hashmaps, sets, .... It also includes a logging system. As well as wrappers around memory allocation/deallocation functions. 5. IPC Resource Manager The IRM implements the API provided in libouroboros-irm by opening a POSIX local IPC socket that listens to messages sent by the libouroboros-irm library. It is a daemon that has 2 functions: - It acts as a broker between the IPC Processes and applications and checks the validity of requests.. - It allows network administrators to construct their RINA network. It holds a directed acyclic graph with all the IPCPs in the system. It is responsible for correctly cleaning up the IPCPs upon shutdown of the network stack. 6. IPC Process Daemon A new IPCP will open a POSIX local IPC socket to listen to messages from libouroboros-ipcp and the IRM when its functions are called. Every type of IPC Process, whether it is a shim IPCP or a normal IPCP, has to provide a factory to instantiate a new IPCP of its type. Internally, a normal IPC Process consists of different components in order to provide IPC to its user. This section provides a short description of every component together with their API. * Flow Manager * The flow manager is the component that manages a flow’s lifecycle. This is the allocation, deallocation and monitoring of every flow. The flow monitor will: - Find the IPCP in the DIF through which the requested application is available. - Map the requested QoS to policies - Negotiate the flow’s characteristics with the destination IPCP, perform access control, ... - Instantiate an FRCT instance associated with the flow - Maintain the negotiated QoS of the flow - Deallocate the flow when requested * Enrollment * Enrollment allows an IPCP to join a DIF. If the IPCP is the first IPCP in the DIF it is just locally bootstrapped. If it is not, it will allocate a flow to an IPCP of the DIF and exchange static and dynamic information. An address is also assigned during enrollment. The prototype will allow assigning addresses from a flat and a topological addressing scheme. After enrollment, the IPCP will be informed about its neighbors and will also allocate a flow to them. * Resource Information Base * The Resource Information Base is the local view the IPCP has of the DIF. It is a partially replicated distributed database. It has a certain model that is the same for every IPCP in Ouroboros. RIB Provider The RIB can only be accessed through the RIB provider. Apart from providing this access, the RIB provider has a publisher/subscriber mechanism. Subscribers can subscribe to certain events happening in the DIF and publishers can publish these events. * Flow and Retransmission Control Task * The Flow and Retransmission Control Task (FRCT), originally known as the Error and Flow Control Protocol (EFCP), provides the flow with flow control and (if needed) retransmission control. It manages the shared state between two protocol machines: the Data Transfer Protocol (DTP) AE and the Data Transfer Control Protocol (DTCP) AE. DTP is for instance concerned with concatenation, multiplexing, reassembly,... DTCP provides flow control and retransmission control. * Relaying and Multiplexing Task * The relaying and multiplexing task has a scheduler to allow scheduling SDUs for different QoS-cubes. It also checks whether or not an incoming PDU was intended for this IPCP. If it is not, it forwards it through an N-1 port-id by consulting the PDU Forwarding Function. * PDU Forwarding Function * This task implements the policy to be used by the RMT to forward PDUs. In the first phase, a link state routing policy will be provided, implemented by a PDU Forwarding Table (PFT) and a PDU Forwarding Table Generator (PFTG). In later iterations, a routing policy based on geometric routing will be added. 7. DIF Allocator The DIF allocator implements the API provided in libouroboros-da by opening a POSIX local IPC socket that listens to messages sent by the IRM. It is a daemon that has 2 functions: - Resolving a DAF name to a DAP - Providing an N-1 DIF over which a DAP is reachable