This section describes how OpenVPN stores its VPN tunnel state during operation.
OpenVPN uses several data structures as storage containers for state information of active VPN tunnels. These are described in this section, together with a little bit of history to help understand the origin of the current architecture.
Whether an OpenVPN process is running in client-mode or server-mode determines whether it can support only one or multiple simultaneously active VPN tunnels. This consequently also determines how the associated state information is wrapped up internally. This section gives an overview of the differences.
In the old v1.x series, an OpenVPN process managed only one single VPN tunnel. This allowed the VPN tunnel state to be stored together with process-global information in one single
This changed, however, in the v2.x series, as new OpenVPN versions running in server-mode can support multiple simultaneously active VPN tunnels. This necessitated a redesign of the VPN tunnel state container structures, and modification of the External Multiplexer and Internal Multiplexer systems. The majority of these changes are only relevant for OpenVPN processes running in server-mode, and the client-mode structure has remained very similar to the v1.x single-tunnel form.
An OpenVPN process running in client-mode can manage at most one single VPN tunnel at any one time. The state information for a client's VPN tunnel is stored in a
context structure is created in the
main() function. That is also where process-wide initialization takes place, such as parsing command line options and reading configuration files. The
context is then passed to
tunnel_point_to_point() which drives OpenVPN's main event processing loop. These functions are both part of the Main Event Loop module.
Because there is only one
context structure present, it can be initialized and cleaned up from the client's main event processing function. Before the
tunnel_point_to_point() function enters its event loop, it calls
init_instance_handle_signals() which calls
init_instance() to initialize the single
context structure. After the event loop stops, it calls
close_instance() to clean up the
When the main event processing loop activates the external or internal multiplexer to handle a network event, it is not necessary to determine which VPN tunnel the event is associated with, because there is only one VPN tunnel active.
An OpenVPN process running in server-mode can manage multiple simultaneously active VPN tunnels. For every VPN tunnel active, in other words for every OpenVPN client which is connected to a server, the OpenVPN server has one
context structure in which it stores that particular VPN tunnel's state information.
To support multiple
context structures, each is wrapped in a
multi_instance structure, and all the
multi_instance structures are registered in one single
multi_context structure. The External Multiplexer and Internal Multiplexer then use the
multi_context to retrieve the correct
context associated with a given network address.
An OpenVPN process running in server-mode starts in the same
main() function as it would in client-mode. The same process-wide initialization is performed, and the resulting state and configuration is stored in a
context structure. The server-mode and client-mode processes diverge when the
main() function calls one of
These functions receive the
context created in
main(). This object has a special status in server-mode, as it does not represent an active VPN tunnel, but does contain process-wide configuration parameters. In the source code, it is often stored in "top" variables. To distinguish this object from other instances of the same type, its
context.mode value is set to
context objects, which do represent active VPN tunnels, have a
context.mode set to
CM_CHILD_TCP, depending on the external transport protocol.
tunnel_server_tcp() perform similar initialization. In either case, a
multi_context structure is created, and it is initialized according to the configuration stored in the top
context by the
When an OpenVPN client makes a new connection to a server, the server creates a new
multi_instance. The latter is registered in the
multi_context, which makes it possible for the external and internal multiplexers to retrieve the correct
context when a network event occurs.
After the main event loop exits, both
tunnel_server_tcp() perform similar cleanup. They call
multi_uninit() followed by
multi_top_free() to clean up the