Source Code Guide
This page is under construction
Directory structure
- cmake: This directory contains some CMake additions for building O7s.
- doc: This directory holds some documentation, most notably the man pages.
- include: Includes public O7s headers for implementing Ouroboros programs and management tools, and some internal headers that expose functions of the library needed by other O7s components.
- src: The main implementation, which holds
- ipcpd: Reference implementation of the different IPCPs. The unicast IPCP implementation has the following components:
- main: The main entry point into the IPCP.
- addr-auth: Address authority. This component is used to assign the addresses to the IPCPs. This is an relic from the RINA implementation and will be redesigned to reflect more accurately that addresses are composed of names of forwarding elements.
- ca: Congestion avoidance module allowing to select different congestion avoidance strategies. Has multiple policies.
- connmgr: Connection manager, it is uses to allocate data transfer (and management) flows between IPCPS.
- Data transfer flows carry N + 1 traffic and some internal traffic for the directory and flow allocator.
- Management flows are used for the routing component. Will be removed as management flows should be implemented by N - 1 broadcast layers. This component is shared with the broadcast IPCP.
- dir: Directory module that is backed by a key-value store mapping hashed N + 1 application names to N addresses.
- dt: The data transfer component creates and manages the actual forwarding elements. A Distributed Hash Table (dht) is the currently implemented policy.
- enroll: Implementation of the enrollment procedure. This component is shared with the broadcast IPCP.
- fa: The flow allocator, which contains the logic and state needed to create, manage and destroy N + 1 flows.
- pff: The packet forwarding function that selects the outgoing flow(s) on which to forward an incoming DT packet. Currently implemented policies allow for a simple, loop-free alternate or multipath capable forwarding table (PFT).
- psched: The packet schedulers that schedule packets coming from N - 1 or N + 1 flows, prioritizing them to be handled by the data transfer component.
- routing: The component that implements the mechanism to populate the PFTs. Currently holds a link-state routing policy to build an adjacency graph of the layer.
- irmd: Reference implementation of a basic IRMd.
- lib: Implementation of various library functions.
- tools: Some tools, such as small test programs and the IPC Resource Management CLI for managing O7s.
- ipcpd: Reference implementation of the different IPCPs. The unicast IPCP implementation has the following components:
Variables
type ! style="width: 10%" | name | Description |
---|---|---|
int | fd | flow descriptor. It's the flow analogue to a file descriptor. |
struct fcrti * | frcti | An instance of the flow and retransmission control task, the logic that implements the FRCP protocol. |
size_t | idx | This idx is an index in the packet buffer (rdrbuff) and used to calculate the location of the packet in reference the base pointer at which the rdrbuff is mapped into each process' memory space. |
struct shm_du_buff * | sdb | shared memory (shm) data unit (du) buffer. The ouroboros 'flavored' skb. An sdb is a (fixed size) buffer that contains the actual packet data and spare space for (future) packet headers (and packet tails such as CRC), in addition to some metadata for managing the buffer (head and tail offset to the start of the packet, total size of the buffer, ...). The term 'data unit' stems from the OSI SDU (service data unit) and PDU (protocol data unit), which were adopted by RINA. |
struct shm_rbuff * | tx_rb, rx_rb, rb | ring buffer. These (small) ring buffers are shared between 2 processes, used to efficiently move packets through the local pipeline. They pass an index that points to an sdb in the rdrbuff, and are the entry and exit structures with which the application (either a user application or an IPCP) interacts with the end-to-end flow. Writing happens to the transmit ring buffer tx_rb, reading from the receive ring buffer rx_rb. |
struct shm_rdrbuff * | rdrb | random deletion ring buffer, a quick-and-dirty memory allocator. The block of memory in which Ouroboros stores actual packet data (and metadata) in a (ring buffer) of sdbs. Packets are allocated at the head of the ringbuffer and removed from the tail. Packets are marked on deletion, and deleting the tail causes a cleanup operation of all marked packets. Needs to be replaced with a more efficient memory allocator at some point. |
Coding Guidelines
Coding guidelines
The coding guidelines of the main Ouroboros stack are similar as those of the Linux kernel (https://www.kernel.org/doc/html/latest/process/coding-style.html) with the following exceptions:
- Soft tabs are to be used instead of hard tabs
- A space is to be inserted between a pointer and its object name upon declaration or in function signatures. Example:
int * a;
instead of
int *a;
Don’t explicitly cast malloc, but do
ptr = malloc(sizeof(*ptr) * len);
When checking for invalid pointers use
if (ptr == NULL)
instead of
if (!ptr)
When in doubt, just browse the code a bit.
Component lifespan
All (sub)components have a similar structure to them.
First their static objects are allocated. If the base object is allocated on the stack, the functions are called init (some internals may be allocated on the heap). If the base object is allocated on the heap (malloc) the functions are called create.
If the object has active components (e.g. spawns internal threads), they will activate as part of a start() call. Do not start threads in an init or create call!
At the end of the object's lifetime, first the threads are stopped (stop()) call, and the object is destroyed via a fini() call if it was living on the stack, or a destroy() call if it was allocated on the heap.
init() / create()
start()
stop()
fini() / destroy()