Skip to main content.

Runnable Userspace Meta Programs


About (top)

Rump (Runnable Userspace Meta Program) is a mechanism for running kernel code as part of a user program's address space. As opposed to executing system calls for requesting kernel services, rump programs do a library call into the kernel code for equivalent functionality. Kernel functionality provided by rump is simply recompiled into userspace from the kernel sources instead of being rewritten, so services imitate the same services being provided by the kernel.

This approach allows:

  • virtualization: every address space has its own instance of state. Furthermore, the functionality does not even need to be equal. For example, multiple different networking stacks optimized for different purposes are possible.
  • isolation: rump functionality runs in its own instance in a userspace process. In case of a security vulnerability or a program error, direct damage to the system is limited to the process running the rump kernel.
  • easy prototyping and development: kernel code can be developed as a normal userspace application. Once development is finished, the code can simply be complied into the kernel.

The approach does not impose a stance on general kernel architecture. Monolithic operation is still possible where desired for example for performance reasons.

There are two possible operating modes for rump. The conceptual difference is further illustrated in Figure 1, “Two operating modes of rump”.

  • In front of the kernel. In this scenario, an application makes explicit calls to rump to request services. In principle, kernel functionality is used like with any other programming library.
  • Behind the kernel. In this scenerio, rump is used more in a server capacity to provide services normally run in kernelspace. It is invisible to regular applications and they cannot tell the difference between regular kernel and rump operation. An example is file servers using kernel file system code.

Figure 1. Two operating modes of rump

Two operating modes of rump


The components currently included in rump are:

All functionality is available in the base system as userspace libraries. For a closer explanation of what functionality is provided by each library, see the chapters on the respective functionality.

Namespaces

Kernel code namepace is designated by providing the _KERNEL preprocessor macro for a module during compilation. Kernel interfaces are not exported to userspace programs except indirectly through system calls. Due to these namespace issues it is not possible to call kernel interfaces directly as function calls from userspace programs.

To address the issue, rump provides some kernel interfaces under an alternate namespace for userspace programs. For example, vnode operations are provided under the name RUMP_VOP_OPER() instead of the regular kernel name VOP_OPER(). However, this is not a final solution and reworking the interface definitions for the entire system would be desireable as a future undertaking. Additionally, rump provides some interfaces for examining types which are opaque to userspace.

Core Components (top)

The core of rump consists of two libraries: librump and librumpuser. The former provides a core necessary to all code running in the kernel. Examples of this core functionality include memory allocation and synchronization primitives. Meanwhile, rumpuser provides a way for code running in kernel space to make system and library calls to the host system. These are used to implement various kernel interfaces in librump. For instance, librump does not itself implement threading and synchronization, but rather uses the host system pthread implementation and merely does interface mapping. Similarly, librump uses the host platform read() and write() system calls to perform mass media access.

rump system calls

One way to access rump services from an application is to use rump system calls. They provide equivalent functionality to real system calls. However, instead of trapping into the kernel, rump system calls provide interface wrappers which make normal function calls to the kernel routines inside of rump. Therefore, the state which they access is not that of the host kernel, but rather that of the faux kernel active in the calling process itself. All rump system calls are provided in the namespace rump_sys. Also, the implicit errno "parameter" of all system calls is explicitly required as the last parameter for rump system calls.

For instance, if a rump application wished to adjust the receive timeout option of a socket it has created, it would issue the call rump_sys_setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv), &rumperrno); instead of calling the normal interface setsockopt(), as this call would be handled by the host kernel running the rump process.

The system calls provided by rump are listed in the header <rump/rump_syscalls.h>.

File Systems (top)

File systems are in essence protocol translators being able to transform the virtual file system protocol into the physical file system protocol. This might be for example disk layout in the case of FFS or a networking protocol in the case of NFS. As this functionality rarely fully available in userspace, this opens up new possibilities for applications. Even if it is already available, the rump solution allows for code reuse without the need for reimplementation.

Currently the following NetBSD kernel file systems are available as rump libraries:

  • cd9660fs, efs, ext2fs, ffs, hfs, lfs, nfs, msdosfs, nfs, ntfs, puffs, tmpfs, and udf

Rump file systems are supported both in front of the kernel and behind the kernel (follow the links for further information):

Figure 2. rump file systems

rump file systems


Networking (top)

Rump provides networking stack support either for in-kernel consumers wishing to networking services or for specifically written user programs wishing to use the kernel networking stack for purposes of virtualization and development.

There are two different modes of operation: full userspace networking stack or host kernel networking stack. The the first case the entire networking stack is run in userspace and is interfaced with the physical network through a tap device. In the latter case, only the kernel sockets layer is run in userspace. A virtual protocol family provides networking access using socket system calls on the host system. The tradeoff between the two is essentially a question of purpose: the latter does not require any interface configuration priviledges and uses the same network address as all other applications on the host. It is useful when using kernel components which just require access to the networking on the abstract sockets layer.

Figure 3. rump networking

rump networking


For an example of how to use rump networking, please see the network test program It is a simple program which connects to www.NetBSD.org, reads index.html, and dumps it on screen. The program shows how to configure a virtual interface and routing and how to open a rump networking socket and how to send and receive data through it.

Futher Information (top)

You can browse the source code history online. See README.dirs in the top level directory for information on what to find where.

The rump manual page provides further programming information: rump(3).