NGI Assure project: Layer-2-Overlay
The next generation testing framework
Netjail setup and execution
Netjail is the GNUnet naming for having several network namespaces, being isolated from each other to test how GNUnet nodes with limited connectivity behave, and how the new transport next generation implementation can help to circumvent the connectivity obstacles. The network namespaces are span a network with globally known nodes and several subnets separated from each other via a single router. We have three scripts for the test setup:
- netjail_start.sh: A script to setup the network namespaces. This script takes three arguments. The first is either the name of a configuration for the test setup topology or a string containing the topology information. The second is the process id of the test. The third is a flag if the first parameter contains the name of the configuration file or the topology string.
- netjail_exec.sh: A script to run some command in a specific namespace. This script takes eight arguments. The first is the index of a node in a namespace for which we like to execute a command. The second is the index of the namespace of the node. The third is the command to execute, the fourth is the number of subnets, the fifth the number of nodes in each subnet, the sixth is the identifier used by the ip-netns command, the sixth is a flag is the topology information is given via a topology file of a string containing the topology information..
- netjail_stop.sh: A script which remove all the network namespace setup by netjail_start.sh. The arguments are the same as those for netjail_start.sh.
CMD helper and testcase plugins
Although netjail_exec.sh can execute an arbitrary command in the ng testing framework a special command is used: gnunet-cmds-helper This commands itself is of a special kind named helper processes which communicates via GNUNET_MessageHeaders on stdin/stdout with the process that started the helper. The gnunet-cmds-helper is used to load testcase plugins. Those plugins are implementations of an api which is used to start different test cases. Those plugins are dynamically loaded by gnunet-cmds-helper. Each plugin defines the commands which are running in a local interpreter loop started by the helper on that specific network namespace node. The plugins are also responsible for the communication via the helper with the master interpreter loop.
Command Pattern
The testing framework borrowed from the GNU Taler testing library was extended to handle asychronous commands. Therefore a struct GNUNET_TESTING_AsyncContext was added to struct GNUNET_TESTING_Command. By default the continuation function of GNUNET_TESTING_AsyncContext is the interpreter_next function of the interpreter loop (blocking asynchronous command) which will be executed calling GNUNET_TESTING_async_finish, when the asynchronous task finished, but also can be any other function to be executed when the asynchronous task is non blocking.
Topology Configuration
The topology of the netjail setup can be configured via a configuration file, or with a configuration string handed over to the generic binary for starting netjail based tests. Both method can be examined in two example test scripts test_transport_send_simple.sh and test_transport_send_simple_string.sh The Syntax of the configuration is as follows. The configuration string is structured by lines and the delimiter ':' used for seperating key/value(s) pairs and the chars '{' and '}' for grouping several key/value pairs as value and '|' to separate a group of values from the key/value(s) pair identifying a line. Below you find the EBNF of the configuration syntax. config = line, {line} ;
line = ( "M:", NumberOfNodesPerSubnet ) | ( "N:", NumberOfSubnets ) | ( "X:", NumberOfGlobalNodes ) | NumberOfAdditionalConnections | ( "T:", GlobalPluginName ) | ( GlobalPeer, "|", KValue ) | ( "R:", IndexOfSubnetRouter, "|", RValue ) | ( SubnetPeer, "|", PValue ) ;
NumberOfNodesPerSubnet = Zero | NaturalNumber ;
NumberOfSubnets = NaturalNumber ;
NumberOfGlobalNodes = NaturalNumber ;
NumberOfAdditionalConnections = "AC:", NaturalNumber GlobalPluginName = "libgnunet_test_transport_plugin_cmd_", PluginName ;
GlobalPeer = "K", ":", IndexOfGlobalNode ;
KValue = EstablishConnectionToPeerViaProtocol ;
IndexOfSubnetRouter = Zero | NaturalNumber ;
RValue = OpenTCP, "|", OpenUDP ;
SubnetPeer = "P:", SubnetIndex, ":", NodeIndexInSubnet ;
PValue = EstablishConnectionToPeerViaProtocol, { "|", "{", NumberOfAdditionalConnections, "}" } ;
Zero = "0" ;
NaturalNumber = NumeralWithoutZero, { Numeral } ;
PluginName = Letter , { ( Letter | "_" ) } ;
IndexOfGlobalNode = Zero | NaturalNumber ;
EstablishConnectionToPeerViaProtocol = "{" "connect", ":" EstablishConnectionToPeerViaProtocolValues "}" ;
OpenTCP = OpenTCPNoSource | OpenTCPWithSource ;
OpenUDP = OpenUDPNoSource | OpenUDPWithSource ;
SubnetIndex = NaturalNumber ;
NodeIndexInSubnet = NaturalNumber ;
NumeralWithoutZero = "0" | Numeral ;
Numeral = "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ;
Letter = "A" | "B" | ... | "Z" | "a" | ... | "z";
EstablishConnectionToPeerViaProtocolValues = EstablishConnectionToPeerViaProtocolValue { "|", EstablishConnectionToPeerViaProtocolValue } OpenTCPNoSource = "{tcp_port:", switch, "}" ;
OpenUDPNoSource = "{udp_port:", switch, "}" ;
OpenTCPWithSource = "{tcp_port:", SubnetPeer, { "tcp_port", SubnetPeer } ;
OpenTUDWithSource = "{udp_port:", SubnetPeer, { "udp_port", SubnetPeer } ;
EstablishConnectionToPeerViaProtocolValue = "{", ( GlobalPeer | SubnetPeer ), ":", Protocol, "}" ;
switch = On | Off ;
Protocol = "tcp" | "udp" ;
On = 1 ;
Off = 0 ;