URT Network Support

The Unix Runtime support for networking implements the interface to the Digital Unix V3.2 networking code. This document describes the socket support, internet initialization utilities, and how we spoof the Digital Unix TCP code to work in SPIN.

Sockets

The URT network support provides a unix-like socket interface to the UDP and TCP protocols. Sockets are based on the BSD socket implemention provided by Digital Unix. The module is a safe interface to the underlying socket implementation. It is written defensively and does not expose the socket represention to untrusted clients. Sockets grants access to the sockets layer by exporting procedures that use those of the in-kernel UNIX system. Thus, Sockets mainly calls these procedures. Currently we only support sockets in synchronous mode, which means that a receive call actually blocks, if there is no data available. Asynchronous socket support has not been tested.

The Socket interface uses mbufs to implement a zero-copy send and receive interface. Outgoing data is transferred immediately to the socket layer without touching that user provided data.

Internet initialization and utilities (In)

Since we borrow some low-level components of the Unix networking source, it is necessary to spoof various components into believing that it is running in the context of Digital Unix.

The In module defines the in_aliasreq and in_ifaddr data structures used to register interface devices (lance, t3, etc.). For each IP address assigned to an interface, an in_ifaddr structure is allocated and added to the interface address list. IP addresses are assigned using the In.Control() procedure define in the In interface.

TCP from Digital Unix V3.2 Plexus supports multiple implementations of the same protocol for different endpoints in the same way that it supports multiple protocols -- different handlers are fired in response to different guard predicates evaluating true. We currently borrow the TCP protocol from Digital Unix. To make TCP work in our environment required that we import other networking modules found in the netinet directory. In particular the following modules are required:

Internet support (in.c). Initializes the internet support and provide utility functions.

Protocol control block (in_pcb.c).

Berkeley Socket support (uipc_socket.c and uipc_socket2.c).

Berkeley memory buffer (uipc_mbuf.c).

TCP input processing (tcp_input.c).

TCP output processing (tcp_output.c).

Miscellaneous TCP support routines (tcp_subr.c).

Functions for slow/fast TCP timeouts (tcp_timer.c).

TCP debugging and tracing utiDTties (tcp_debug.c).

Berkeley protocol software table (tcp_usrreq.c). Used to glue socket operations with protocol operations.

URT defines a OsfNet module that initializes the TCP module, starts the fast and slow TCP timers, initializes a protocol software table (protosw) and unix domain structure for TCP, implements the pffindtype() function to return the protosw structure, and provides the interface to call TCP's input routine. In relation to the Plexus osfClient, OsfNet does the top-level initialization of internal datastructures, whereas the osfClient passes packets to the Digital Unix networking code. Rather than littering the networking C code with SPIN specific #ifdef statements, URT's net_upcall modules defines the C functions and globals used by the networking code. The net_upcalls module provides upcalls (via procedure variables), and global variables and dummy functions that are used to spoof the networking tcp C code to believe it is running in a environment. There are a few functions that the networking code calls that are redirected to a Modula-3 implementation provided by URT. The redirection is achieved via procedure variables that are bound to the Modula-3 implementation at URT initialization. The following procedures are currently redirected:
ip_output(). Redirected to the IP output function provided by Plexus.

pffindtype (). Redirected to OsfNet provided by URT.

Network Synchronization and Socket Locking

The networking code (tcp and sockets) use reader/writer lock primitives for synchronization. Specifically, TCP time out functions, TCP input and output processing, and all accesses to protocol control blocks (pcb) and sockets are synchronized using locks. These locks are used when setting the #define NETSYNC_LOCK to TRUE in net/net_globals.h. The lock primitives (ulock_xxx ops) are emulated by SPIN and are implemented by ThreadForSAL

The net_upcalls.c file defines the following functions and global variables related to synchronization:

solock() and sounlock() call solock_ext() and sounlock_ext(), respectively, and are called to synchronize on socket operations.
route_lock, inifaddr_lock, igmp_lock and inp_udp_li are global lock data structures that are initialized explicitly by the OsfNet module.
lockmode is set to the preemptive kernel lock mode. (lockmode=1)

Global Variables

The following global variables are linked by the networking C code:
struct in_ifaddr *in_ifaddr; is the head of the in_ifaddr structure list, which is used by the in.c module.

unsigned char inetctlerrmap[24]; is defined but not used.

struct protosw inetsw[1]; is previously used by the pffindtype() function, which is now implemented by the OsfNet module.

struct ifqueue ipintrq; must be defined, but is not used.
struct ifnet loif; must be defined, but is not used.

Dummy Functions

The networking code is functional without various support functions. The following list of dummy functions either do nothing or return a default value (typically 0 or 1).

Many of the above functions are used to optimize the packet processing path through the networking code. The inaction of these functions simply forces the networking code to follow a more general and slower path.


Marc Fiuczynski
DAY/MONTH/YEAR