From 0e4e96b9bf56d3fdbd8db7b4cf5b66b4a34bf4d3 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Fri, 15 Nov 2019 10:49:25 -0500 Subject: [PATCH 1/2] High-level documentation of configuration in Tor. Closes ticket 32209. --- src/lib/conf/config.md | 126 +++++++++++++++++++++++++++++++++++++++++ src/mainpage.md | 3 +- 2 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 src/lib/conf/config.md diff --git a/src/lib/conf/config.md b/src/lib/conf/config.md new file mode 100644 index 0000000000..4dff316dc4 --- /dev/null +++ b/src/lib/conf/config.md @@ -0,0 +1,126 @@ + +@page configuration Configuration options and persistent state + +@tableofcontents + +## Introduction + +Tor uses a shared, table-driven mechanism to handle its +configuration (torrc) files and its state files. Each module can +declare a set of named fields for these files, and get notified +whenever the configuration changes, or when the state is about to be +flushed to disk. + +## Declaring options + +Most modules will only need to use the macros in confdecl.h to +declare a configuration or state structure. + +You'll write something like this: + + // my_module_config.inc + BEGIN_CONF_STRUCT(module_options_t) + CONF_VAR(FieldOne, INT, 0, "7") + CONF_VAR(FieldTwo, STRING, 0, NULL) + END_CONF_STRUCT(module_options_t) + +The above example will result in a structure called module_config_t +with two fields: one an integer called FieldOne and one a string +called FieldTwo. The integer gets a default value of 7; the +string's default value is NULL. + +After making a definition file like that, you include it twice: once +in a header, after saying \#define CONF_CONTEXT STRUCT, and once in +a C file, after saying \#define CONF_CONTEXT TABLE. The first time +defines a module_options_t structure, and the second time defines a +table that tells the configuration manager how to use it. + +Using the table, you declare a `const` config_format_t, which +associates the fields with a set of functions for validating and +normalizing them, a list of abbreviations and deprecations, and +other features. + +See confdecl.h and conftypes.h for more information. For example +usage, see crypto_options.inc or mainloop_state.inc. + +## Getting notifications + +After using those macros, you must tell the subsystem management +code about your module's configuration/state. + +If you're writing configuration code, you'll need a function that +receives the configuration object, and acts upon it. This function +needs to be safe to call multiple times, since Tor will reconfigure +its subsystems whenever it, or whenever it restarts in process. +This function goes in your subsystem's subsys_fns_t.set_options +field. + +If you're writing state code, you'll need a function that receives +state (subsys_fns_t.set_state), and a function that flushes the +application state into a state object (subsys_fns_t.flush_state). +The `set_state` function will be called once (@ref config_once_per +"1") when Tor is starting, whereas the `flush_state` function will +be called whenever Tor is about to save the state to disk. + +See subsys_fns_t for more information here, and \ref initialization +for more information about initialization and subsystems in general. + +> @anchor config_once_per 1. Technically, state is set once _per startup_. +> Remember that Tor can be stopped and started multiple times in +> the same process. If this happens, then your set_state() function +> is called once every time Tor starts. + +## How it works + +The common logic used to handle configuration and state files lives +in @refdir{lib/confmgt}. At the highest level, a configuration +manager object (config_mgr_t) maintains a list of each module's +configuration objects, and a list of all their fields. When the +user specifies a configuration value, the manager finds out how to +parse it, where to store it, and which configuration object is +affected. + +The top-level configuration module (config.c) and state module +(statefile.c) use config_mgr_t to create, initialize, set, compare, +and free a "top level configuration object". This object contains a +list of sub-objects: one for each module that participates in the +configuration/state system. This top-level code then invokes the +subsystem manager code (subsysmgr.c) to pass the corresponding +configuration or state objects to each module that has one. + +Note that the top level code does not have easy access to the +configuration objects used by the sub-modules. This is by design. +A module _may_ expose its configuration or state object, if it +likes, but if it does not, that object should be considered +module-local. + +## Adding new types + +Configuration and state fields each have a "type". These types +specify how the fields' values are represented in C; how they are +stored in files; and how they are encoded back and forth. + +There is a set of built-in types listed in conftypes.h, but +higher-level code can define its own types. To do so, you make an +instance of var_type_fns_t that describes how to manage your type, +and an instance of var_type_def_t that wraps your var_type_fns_t +with a name and optional parameters and flags. + +For an example of how a higher-level type is defined, see +ROUTERSET_type_defn in routerset.c. Also see the typedef +`config_decl_ROUTERSET`. Together, these let the routerset type be +used with the macros in confdecl.h. + +## Legacy configuration and state + +As of this writing, most of the configuration and state is still +handled directly in config.c and statefile.c, and stored in the +monolithic structures or_options_t and or_state_t respectively. + +These top-level structures are accessed with get_options() and +get_state(), and used throughout much of the code, at the level of +@refdir{core} and higher. + +With time we hope to refactor this configuration into more +reasonable pieces, so that they are no longer (effectively) global +variables used throughout the code. diff --git a/src/mainpage.md b/src/mainpage.md index a2c5ec6302..c5cb1af235 100644 --- a/src/mainpage.md +++ b/src/mainpage.md @@ -41,6 +41,8 @@ Tor repository. @subpage time_periodic +@subpage configuration + @page intro A high-level overview @@ -140,4 +142,3 @@ more connection types. A 'Node' (node_t) is a view of a Tor instance's current knowledge and opinions about a Tor relay or bridge. - From 55fac8dafc78d1f9ea6b15f2eadc0975ade9667d Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Thu, 21 Nov 2019 08:26:12 -0500 Subject: [PATCH 2/2] config.md: suggestions from teor --- src/lib/conf/config.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/lib/conf/config.md b/src/lib/conf/config.md index 4dff316dc4..7741e21f42 100644 --- a/src/lib/conf/config.md +++ b/src/lib/conf/config.md @@ -48,12 +48,12 @@ usage, see crypto_options.inc or mainloop_state.inc. After using those macros, you must tell the subsystem management code about your module's configuration/state. -If you're writing configuration code, you'll need a function that -receives the configuration object, and acts upon it. This function -needs to be safe to call multiple times, since Tor will reconfigure -its subsystems whenever it, or whenever it restarts in process. -This function goes in your subsystem's subsys_fns_t.set_options -field. +If you're writing configuration code, you'll need a function that receives +the configuration object, and acts upon it. This function needs to be safe +to call multiple times, since Tor will reconfigure its subsystems whenever it +re-reads the torrc, gets a configuration change from a controller, or +restarts in process. This function goes in your subsystem's +subsys_fns_t.set_options field. If you're writing state code, you'll need a function that receives state (subsys_fns_t.set_state), and a function that flushes the @@ -89,10 +89,10 @@ subsystem manager code (subsysmgr.c) to pass the corresponding configuration or state objects to each module that has one. Note that the top level code does not have easy access to the -configuration objects used by the sub-modules. This is by design. -A module _may_ expose its configuration or state object, if it -likes, but if it does not, that object should be considered -module-local. +configuration objects used by the sub-modules. This is by design. A +module _may_ expose some or all of its configuration or state object via +accessor functions, if it likes, but if it does not, that object should +be considered module-local. ## Adding new types @@ -113,8 +113,8 @@ used with the macros in confdecl.h. ## Legacy configuration and state -As of this writing, most of the configuration and state is still -handled directly in config.c and statefile.c, and stored in the +As of this writing (November 2019), most of the configuration and state is +still handled directly in config.c and statefile.c, and stored in the monolithic structures or_options_t and or_state_t respectively. These top-level structures are accessed with get_options() and