24 KiB
Configuring Serval DNA
Serval Project, April 2013
Configuration options
The servald configuration is an unordered set of LABEL=VALUE pairs called options. For example:
debug.verbose=true
interfaces.0.file=/var/tmp/serval/dummy
interfaces.0.socket_type=file
log.file.directory_path=/var/tmp/serval-logs
log.file.duration=20m
log.file.rotate=10
rhizome.direct.peer.0.host=129.96.12.91
server.respawn_on_crash=true
An option LABEL is a sequence of one or more US-ASCII alphanumeric
words separated by period characters, eg, log.file.directory_path
. If a
LABEL is not recognised, it is unsupported.
An option VALUE is a string of US-ASCII characters, excluding newline (character 10), which is parsed according to the option's type:
- decimal integer, eg:
10
,0
,-1000000
- boolean, eg:
true
,false
,on
,off
,1
,0
,yes
,no
- internet address (in_addr), eg:
192.168.1.1
- time interval, eg:
12h
,1w3d
,2h15m30s
- absolute path, eg:
/var/lib/serval
- relative path, eg:
../lib/hostlist
- Serval ID (SID), eg:
EEBF3AC19E7EE58722A0F6D4A4D5894A72F5C71030C3399FE75808DCF6C6254B
- scaled decimal integer with optional suffix k (10^3), K (2^10),
m (10^6), M (2^20), g (10^9) or G (2^30), eg:
1M
= 1,048,576
If a VALUE does not parse correctly, it is invalid.
Instance directory
By default, servald stores its configuration, keyring, and other temporary
files in its instance directory. The instance directory is set at run time
by the SERVALINSTANCE_PATH
environment variable. If this is not set, then
servald uses a built-in default path which depends on its build-time option
and target platform:
- as specified by the
./configure INSTANCE_PATH=<path>
option when servald was built from source - on Android
/data/data/org.servalproject/var/serval-node
- on other platforms
/var/serval-node
servald will create its instance directory (and all enclosing parent directories) if it does not already exist.
Configuration persistence
servald stores its configuration option settings in a file called
serval.conf
in its instance directory. It reads this file upon every
invocation. This means that each instance's option settings persist until
changed or until its serval.conf
file is altered or removed.
The format of the file is as shown in the example above: each option is represented by a single line in the file. Each line may have one of the forms:
[ WHITE ] LABEL "=" VALUE "\n"
[ WHITE ] "#" COMMENT "\n"
[ WHITE ] "\n"
where WHITE is any sequence of zero or more space or tab characters (as classified by isspace(3)), COMMENT is any sequence of characters except newline, and LABEL and VALUE are as defined above.
Blank lines are ignored, as are lines beginning with the comment character #
.
VALUE is parsed very strictly: all spaces are significant. A leading or
trailing space in VALUE can cause a numerical option to be invalid.
Invalid configuration
Although serval.conf
is usually written and read only by servald, in fact
it is an external file which may be modified, so servald has no control
over its contents. The semantics of the configuration loading anticipate the
possibility of encountering a defective file:
-
If
serval.conf
is syntactically malformed, then servald will log a warning, skip the malformed line and continue parsing; -
If the same LABEL appears more than once, then servald will log a warning and ignore the second and all subsequent lines with the duplicate LABEL;
-
If an unsupported LABEL is encountered (which could be a mis-spelling of a supported option), then servald will log a warning and ignore the line;
-
If a configuration option has an invalid VALUE, then servald will log a warning and leave the option with its built-in default value;
-
If a logical relation, such as mutually incompatible or mandatory options, is violated, then servald will log a warning and ignore the illogical options or use default values.
In all the above cases, most servald commands will reject the defective file by logging an error and exiting with error status (255). In this case, logging is done using options salvaged from the defective file (see the config dump command, described below).
Some “permissive” commands, such as help
, stop
, and the various config
commands described below, will not fail on a defective configuration file.
Instead they will log a warning and carry on using options salvaged from the
defective file. This means that servald may always be used to inspect and
correct the configuration, and to stop a running daemon, despite a defective
configuration file.
Daemon processes
To run more than one servald daemon process on the same device, each daemon
must have its own instance path (and hence its own serval.conf
). Set the
SERVALINSTANCE_PATH
environment variable to a different directory path before
starting each daemon.
As described above, a defective serval.conf
will prevent the servald
start
command from starting a daemon process. Once the daemon is running, it
periodically checks whether serval.conf
has changed (by comparing size and
modification time) and attempts to re-load it if it detects a change. If the
re-loaded file is defective, the daemon rejects it, logs an error, and
continues execution with its prior configuration unchanged. If the daemon is
stopped or killed, it cannot be re-started while serval.conf
remains
defective.
About the examples
The examples in this document are Bourne shell commands, using standard
quoting and variable expansion. Commands issued by the user are prefixed with
the shell prompt $
to distinguish them from the output of the command.
Single and double quotes around arguments are part of the shell syntax, so are
not seen by the command. Lines ending in backslash \
continue the command on
the next line.
Configuration commands
config set
To set a configuration option:
$ servald config set name.of.option 'value'
$
config del
To unset (remove) a configuration option, returning it to its default value:
$ servald config del name.of.option
$
config set del
Several set and del commands can be chained together in a single command:
$ servald config set debug.verbose 1 \
del debug.dnahelper \
set log.file.path /tmp/log.txt
$
config get
To examine a single option's current value as defined in the serval.conf
file
(invalid, unsupported and illogical options may be examined, but not duplicate
options):
$ servald config get name.of.option
name.of.option=value
$
To examine all option settings defined in the serval.conf
file, including
invalid, unsupported and illogical options, but not duplicate options:
$ servald config get
interfaces=+eth0,+wifi0
name.of.option=value
name.of.other_option=value2
$
config schema
To list the names and types of all supported configuration options (the “configuration schema”):
$ servald config schema
debug.broadcasts=(boolean)
debug.dnahelper=(boolean)
debug.dnaresponses=(boolean)
...
server.chdir=(absolute_path)
server.interface_path=(str_nonempty)
server.respawn_on_crash=(boolean)
$
The configuration schema, with its default values, is defined in the conf_schema.h source header file.
config dump
To examine all current valid configuration option settings, as produced by
parsing serval.conf
and omitting invalid, unsupported, duplicate and
illogical options (ie, the configuration used by permissive commands and for
logging):
$ servald config dump --full
debug.broadcasts=false
debug.dnahelper=false
debug.dnaresponses=false
...
rhizome.rhizome_mdp_block_size=512
server.chdir=/
server.respawn_on_crash=true
$
Omitting the --full
argument omits all options which have their default
value, leaving only the minimal settings that need be present in serval.conf
to produce the current configuration:
$ servald config dump
debug.rhizome=true
interfaces.0.file=/var/serval-node/dummy
interfaces.0.socket_type=file
rhizome.direct.peer.0.host=129.128.127.126
server.respawn_on_crash=true
$
Logging configuration
servald logging is controlled by the following config options:
log.console.level=debug|info|hint|warn|error|none
log.console.dump_config=BOOLEAN
log.console.show_pid=BOOLEAN
log.console.show_time=BOOLEAN
log.android.level=debug|info|hint|warn|error|none
log.android.dump_config=BOOLEAN
log.android.show_pid=BOOLEAN
log.android.show_time=BOOLEAN
log.file.level=debug|info|hint|warn|error|none
log.file.dump_config=BOOLEAN
log.file.show_pid=BOOLEAN
log.file.show_time=BOOLEAN
log.file.path=PATH
log.file.directory_path=PATH
log.file.duration=INTERVAL
log.file.rotate=UINT
There are three log output destinations, each of which can be configured independently of the others:
-
The console log destination is the standard error of the servald process, which is available in all command invocations of servald, but not in the background daemon process (the daemon closes all its standard IO streams when started in background mode).
-
The android log destination is available in servald executables built for the Android platform, and sends to the Android Log buffer that is accessible via the
adb logcat
command. On non-Android platforms, thelog.android
configuration options are supported but have no effect. -
The file log destination is a log file created and appended directly by the servald process using the O_APPEND option of open(2) and a single write(2) system call per log line (so concurrent servald processes will not corrupt each others' log lines). If the file does not exist, servald will create it and all its enclosing directories as needed.
All log destinations support the following configuration options:
-
log.DESTINATION.level
Log messages below this level are not sent to the destination. The lowest level isdebug
, and the highest iserror
. Setting this option tonone
suppresses all log messages. -
log.DESTINATION.dump_config
If true, then the current configuration is written to the destination (inservald config dump
format), prior to other messages. -
log.DESTINATION.show_pid
If true, then every line written to this destination is prefixed with the Process ID of the process that produced it. -
log.DESTINATION.show_time
If true, then every line written to this destination is prefixed with the system time in millisecond resolution (if available) in the formatHH:MM:SS.mmm
.
In addition, the file destination has these extra configuration options:
-
log.file.directory_path
If set, log files are created in this directory, which is created if it does not exist. This defaults to thelog
directory within the instance directory. -
log.file.path
If set, all log messages are appended directly to the file at the given path. If the path is not absolute, it is interpreted relative thelog.file.directory_path
option. Iflog.file.path
is not set, then log files have names of the formserval-YYYYMMDDHHMMSS.log
, using the date/time of creation of the file. -
log.file.duration
If non zero, then a new log file is created every new interval. Interval boundaries are measured from the Unix epoch, so if the interval is an integral divisor of one day then a new file will always start at midnight. The interval can be given as a plain number of seconds, but a convenient scaled notation is supported:[Nw][Nd][Nh][Nm][N[s]]
, eg,2h40m20s
means two hours plus 40 minutes plis 20 seconds. -
log.file.rotate
If non zero, then old log files are deleted so that no more than this many files exist at one time.
Every log message is written to all destinations according to their configuration.
Network interfaces
The servald daemon periodically scans its operating system's network
interfaces and uses its interfaces
configuration option to select which to
ignore and which to use.
For example, the following configuration will use any interface whose name
starts with eth
(eg, eth0
, eth1
) on port 7333 and any interface whose
name starts with wifi
or wlan
but is not wifi0
or wlan0
as a Wi-Fi
on the default port number:
$ servald config set interfaces.0.match 'eth*' \
set interfaces.0.type ethernet \
set interfaces.0.port 7333 \
set interfaces.1.match 'wifi0,wlan0' \
set interfaces.1.exclude true \
set interfaces.2.match 'wifi*,wlan*' \
set interfaces.2.type wifi
The following configuration is equivalent to the above example, but uses the “legacy”, single-option syntax (see below):
$ servald config set interfaces \
'+eth=ethernet:7333,-wifi0,-wlan0,+wifi=wifi,+wlan=wifi'
The following two equivalent configurations will use all available interfaces, treating all as Wi-Fi (the default type) with a 400 µs inter-packet delay (the default packet interval for Wi-Fi):
$ servald config set interfaces.0.match '*'
$ servald config set interfaces '+'
Network interface rules
As shown in the first example above, the interfaces
config option contains a
numbered list of rules that are applied to all detected system interfaces in
order of ascending number. The general form of an interface rule is:
interfaces.UINT.match=PATTERN[, PATTERN ...]
interfaces.UINT.file=PATH
interfaces.UINT.exclude=BOOLEAN
interfaces.UINT.socket_type=SOCKTYPE
interfaces.UINT.port=PORT
interfaces.UINT.encapsulation=ENCAPSULATION
interfaces.UINT.default_route=BOOLEAN
interfaces.UINT.prefer_unicast=BOOLEAN
interfaces.UINT.send_broadcasts=BOOLEAN
interfaces.UINT.type=IFTYPE
interfaces.UINT.mdp_tick_ms=UINT_NONZERO
interfaces.UINT.packet_interval=UINT_NONZERO
where:
- PATTERN is a shell wildcard pattern
- BOOLEAN is
true
,false
,1
,0
,yes
,no
,on
oroff
- SOCKTYPE is
dgram
,stream
orfile
- ENCAPSULATION is
overlay
orsingle
- IFTYPE is
wifi
,ethernet
,catear
orother
- PORT is an unsigned decimal integer in the range 1 to 65535
- UINT is any unsigned decimal integer (with no
+
or-
prefix) - UINT_NONZERO is an unsigned decimal integer ≥ 1
- PATH is an absolute or relative file path
- IN_ADDR is an Internet address as accepted by inet_aton(3), ie,
N.N.N.N
whereN
is an integer in the range 0 to 255.
The match
and file
options are mutually incompatible. If both are set, it
is an error; the interface rule is omitted from the configuration and
serval.conf
is treated as defective (see above). If neither are set, it is
also an error.
If a rule specifies a match
option, then each PATTERN is applied to the names
of the real system interfaces using the fnmatch(3) standard library
function. If any PATTERN matches, then the rule's exclude
option is checked:
if true, then the interface is not activated, otherwise a socket on that system
interface is opened and the interface's socket_type
is set to dgram
. (It
is invalid to explicitly set socket_type
to other than dgram
for a match
interface.)
If a rule specifies a file
path, then an interface is created if the given
file exists. The interface's socket_type
determines how the file is written
and read:
-
file
(the default) creates a “dummy” interface for closed communication with other servald daemons on the same host -- see below. If the file does not exist, a warning is logged and the interface is not activated. -
stream
reads and writes the file as though it were a character special device. If the file does not exist, an error is logged and the interface is not activated. -
dgram
is not valid for a file interface.
The type
option only affects the default settings the packet_interval
and
mdp_tick_ms
options, for convenience. In future it may also change the way
the interface behaves, for example, an ethernet
interface may automatically
assume that broadcast packets will be filtered out, so will start using MDP
unicast protocols immediately rather than waiting to detect that broadcast
packets are not acknowledged.
The packet_interval
option controls the maximum rate at which packets are
tramsmitted on the interface. It sets the average interval, in microseconds,
between individual packets. If the interval is less than the time it takes to
transmit a packet, then packets will be sent at maximum speed with no
intervening delay. Otherwise, delays are inserted between packets as needed to
keep to the average.
The mdp_tick_ms
option controls the time interval, in milliseconds, between
MDB broadcast announcements on the interface. If set to zero, it disables MDP
announcements altogether on the interface (called “tickless” mode). If not
set, then the value of the mdp.iftype.IFTYPE.tick_ms
option is used. If that
is not set, then servald uses a built-in interval that depends on the
IFTYPE.
The encapsulation
option controls how MDP packets are written to the
interface's socket:
overlay
(the default) stuffs as many MDP packets as it can into each UDP frame, to avoid wasting bandwidth on conventional Wi-Fi interfaces which have a fixed packet size (the IEEE 802.11 MTU) over the air;single
sends each MDP packet on its own to the socket using SLIP encoding, and is suited to data links with a variable packet size on the air (eg, a serial connection to a packet radio modem).
The default_route
option, if true, causes all MDP packets with an unresolved
recipient address (SID) to be sent to this interface instead of just dropped.
This will allow the node to use Serval Infrastructure to route its packets.
Many interfaces may have the default_route
set to true, but only the first
one will be used as the default route.
The prefer_unicast
option, if true, causes the interface to send to unicast
IP addresses instead of the broadcast IP address if both have been observed to
reach the destination.
The send_broadcasts
option, if false, prevents the interface from sending any
broadcast packets whenever a recipient address (SID) cannot be resolved to an
interface. Normally, any MDP packet to an unresolvable recipient gets
broadcast on all active interfaces.
Network interface “legacy” syntax
Instead of using the multi-option schema described above, the interfaces
configuration option can be set using a less capable “legacy” format, for
compatibility with older config files. The “legacy” interfaces syntax is a
single text string consisting of a comma-separated list of rule stanzas, each
stanza having one of the following forms:
+
-
+PREFIX=IFTYPE
+PREFIX=IFTYPE:PORT
+PREFIX=IFTYPE:PORT:IGNORED
-PREFIX
+>PATH
The rule +
matches all interfaces.
The rule -
excludes all interfaces.
Rules beginning with +PREFIX
match any interface whose name starts with
PREFIX
; so for example a rule starting with +foo
is equivalent to a match
option with a single PATTERN of foo*
The rule -PREFIX
excludes interfaces whose name starts with PREFIX
.
The rule +>PATH
specifies a dummy interface (see below) with no address or
netmask or broadcast filter.
Interface rules are numbered in the order they appear, and are applied in that
order. For example, an interfaces
option of +,-eth0
will not reject the
eth0 interface because the leading +
will match it first, but -eth0,+
will reject eth0 and accept all others.
The “legacy” format is only provided for backward compatibility and will eventually be deprecated and removed. The “legacy” interfaces configuration is incompatible with the modern form; an instance that uses one cannot use the other.
Dummy network interface
Sometimes it is helpful to run an isolated group of connected servald instances on a single machine for testing purposes. To make this possible, servald supports a dummy network interface.
A dummy interface is simply a regular file to which all instances append their network packets. The file grows without limit. Each instance advances its own read pointer through the file, packet by packet, skipping packets which are not addressed to it. A single dummy file simulates a lossless mesh network with total connectivity, ie, all nodes that read and write the file are neighbours.
To use a dummy interface, first create an empty file, eg, /tmp/dummy
, and for
each servald instance, include the dummy file in its interfaces list, eg:
$ servald config set interfaces.0.file '/tmp/dummy'
NOTE: Because dummynets are files, not sockets, the poll(2) system call does not work on them. As a result the servald daemon main loop has slightly different behaviour and timing characteristics when a dummynet is in use.
If a dummy interface's file
PATH is not absolute (ie, does not start with
/
) then it is interpreted relative to the instance directory.
The following config options adorn a dummy interface with properties that real interfaces normally obtain directly from the operating system:
interfaces.UINT.dummy_address=IN_ADDR
interfaces.UINT.dummy_netmask=IN_ADDR
interfaces.UINT.drop_unicasts=BOOLEAN
interfaces.UINT.drop_broadcasts=BOOLEAN
The dummy_address
option sets the interface's unicast (receive) IP address.
The dummy_netmask
option sets the interface's unicast (receive) IP network
mask, which together with dummy_address
determines the interface's IP
broadcast address.
The drop_unicasts
, option, if true, will drop overlay frames addressed to the
interface's unicast IP address, so that only broadcast packets will be read.
The drop_broadcasts
, option, if true, will drop overlay frames addressed to
the interface's broadcast IP address, so that only unicast packets will be
read. This can simulate the effects of the Fi-Fi drivers on some Android
devices that filter out broadcast packets (to prevent the device from waking up
unless there is traffic explicitly sent to it).