-
Notifications
You must be signed in to change notification settings - Fork 2
Extending
This page briefly describes the process of extending the NFV-TestPerf framework to include additional network solutions and test cases.
- Including new testing applications
- Including new DPDK-compatible virtual switches
- Including new non-DPDK-compatible virtual switches
The testing application (called testapp
) is organized as a BusyBox-like program that contains multiple applications linked together as a single executable file. The applications share the set of accepted parameters and all follow the same internal structure, with minor differences.
To add a new custom test application to the set, you'll have first to add a new source file that will contain the code of your application. Then it shall be included inside the list of testapp's source files, and a main
-like function shall be made visible for the actual main
of testapp.
Following is an example that creates a custom app named test
to be included inside testapp. First, the test.c
source file shall be placed inside the root directory of the testapp source tree.
The file shall be linked against the main program to be visible, and it shall export a non-static function that shall be visible from within testapp's main source file. To achieve this goal, the application Makefile must be edited to include a reference to the new source file, as follows:
SRCS-y += test.c
Place the line above along with the other source files listed inside that Makefile.
Once the file is correctly included inside the build process, it shall include a main
-like function that will accept the parameters of the application. By convention, this function should be called test_body
, though it can be anything else, as long as it has the following signature, which is the same as any C program's main
function:
int test_body (int argc, char* argv[]);
This function shall not be declared static
, as it shall be invoked by testapp's main
function. Any other function that is placed inside the test.c
source file can be declared static
.
Finally, the test_body
function shall be included in the list of available applications inside testapp. To do so, edit the main.h including the name of the application ("test"
) and the function that shall be executed (test_body
) like in the following example:
// Declare your function as extern, so no additional
// include files are required when compiling main.c
extern int test_body (int, char*[]);
static const char *const commands_n[] = {
"server",
"client",
// ...
"test",
};
static const main_body_t commands_f[] = {
server_body,
client_body,
// ...
test_body,
};
Remember to maintain the same ordering for both string arrays.
Now you can compile your application inside testapp by running make
. Once done, you can run it using
./testapp test [args]
All applications included in testapp should follow the same structure. The test_body
function shall abide by the following structure:
int test_body (int argc, char *argv[])
{
struct config conf = CONFIG_STRUCT_INITIALIZER;
// Set the default configuration of the application inside the conf data structure
// ...
// Parse parameters like all other applications
int argind = parameters_parse(argc, argv, &conf);
argc -= argind;
argv += argind;
// If your application uses DPDK then initialize it here
// with the following parameters
int res = dpdk_init(argc, argv, &conf);
if (res) return EXIT_FAILURE;
// Printing the current configuration can be useful
print_config(&conf);
// Create sockets and other long-lasting resources inside the conf data structure
// ...
// The program should run indefinitely until a SIGINT is received.
// The handler should print test results and exit the application.
signal(SIGINT, handle_sigint);
// Loop function, never exits, the program terminates after
// the execution of the handle_sigint function
main_loop(&conf);
}
The parameters_parse
, print_config
, and handle_sigint
functions are included within other common source files of testapp. If possible, your application should accept the same set of parameters of all other testing applications (including both DPDK and non-DPDK-related parameters). If you need additional arguments that are not already included, consider modifying the struct config
data structure and the parse_parameters
function to fit your needs.
The main_loop
functions should instead be defined as static
inside the test.c
file, and it should be structured as follows:
// main loop function shall not return because the signal handler for SIGINT
// terminates the program
static inline void main_loop (struct config *conf) __attribute__((noreturn));
#define ever \
; \
;
static inline void main_loop (struct config *conf)
{
// ----------------------------- Constants ------------------------------ //
// Declare your constants here
// ------------------- Variables and data structures -------------------- //
// Declare your variables and data structures here,
// including packet buffers, headers, timers, stat variables, and other resources
// --------------------------- Initialization --------------------------- //
// Initialize each variable
// ------------------------- Infinite loop body ------------------------- //
// Infinite loop
for (ever)
{
// Save and reset stats once every second
// Prepare and exchange packets, updating stats each time
}
__builtin_unreachable();
}
If your application collects stats using the included API, the execution of the handle_sigint
function will print the collected stats (though by default more than the last 64 entries can be stored, this value can be changed before compiling the application).
The sources of testapp include a number of functions that can be used to both prepare and exchange packets using both traditional sockets and DPDK ports (either virtio
-based or physical compatible ports). For this reason, the inclusion of additional applications designed to work with virtio
-based ports or DPDK-compatible ones is straightforward and requires only the new application logic to be implemented on top of the existing code structure. Check whether some functionality is already included before implementing your own.
If the added application is intended to support some non-DPDK-compatible or non-virtio-compatible framework, it may require additional work in terms of parameters and low-level functionality implementation.
Finally, all you need to do is to write a configuration file that includes your application name inside the LXC_CONT_CMDNAMES
list. Refer to the configurations folder for examples. This should be enough for you to run tests using the run_local_test.bash and other related scripts.
Configuration files specify which applications should be deployed in which LXC container, while the actual virtual switch that should be used to run them must be specified as a command-line option for the related script.
DPDK and virtio
-compatible virtual switches support can be easily added to this framework. The applications included in the testapp
executable will automatically be compatible with it, as long as it is correctly handled by the framework.
Following is the description of the process required to include such a virtual switch/networking framework.
The first step is to include an entry inside the installation script to handle framework installation and removal. Since this step is straightforward, we will not discuss it in details.
Once the new virtual switch implementation is installed by the framework on the system, the run_local_test.bash script shall be modified to start correctly the virtual switch and connect testing applications to it.
As a general example, suppose we want to execute a virtual switch implemented by the vswitch-run
command. We need to include the said virtual switch in the list of valid virtual switches like follows (supposing we want to call it "vswitch-name"
):
vswitch_list="pmd vpp ovs ... vswitch-name"
This instructs the script to accept "vswitch-name"
as a valid virtual switch option. When run, the script will set the vswitch
variable to "vswitch-name"
and it provides two functions to start/stop the selected virtual switch, conveniently called start_vswitch
and stop_vswitch
respectively. Each function is composed by a case
block, in which an option for the given virtual switch must be included, like follows:
function start_vswitch() {
echo "Attempting to start the vswitch..."
case $vswitch in
# ...
vswitch-name)
# Execute the vswitch-run in background with the appropriate parameters here,
# wrapping it inside a separate screen
screen -d -S screen_vswitch `log_vswitch_option` -m \
vswitch-run <args>
;;
# ...
esac
}
function stop_vswitch() {
echo "Stopping vswitch..."
case $vswitch in
# ...
vswitch-name)
# Either kill it by sending the appropriate signal
# to the screen wrapping it (in this example Ctrl+C)
screen -S screen_vswitch -p 0 -X stuff "^C" || true
# And then wait for it to finish
wait_screen screen_vswitch
# Or just kill the executable if you feel more like it
pkill vswitch-run
;;
# ...
esac
}
That's basically it. Other scripts rely on the run_local_test.bash to provide additional services, so the only script to be modified is this one. Of course, make sure that the arguments you give to the command starting the virtual switch will create the ports specified in the loaded configuration file by checking the LXC_XXXXXXX
variables (refer to the configurations folder for more details).
From this simple description, it is clear how the inclusion of such a switching solution is straightforward.
This is not so straightforward as in the previous section for a number of reasons. First of all, the applications currently included in the testapp executable are only compatible with POSIX sockets or DPDK-compatible network ports (including virtio
ones), thus if you want to include another incompatible framework they must be modified to support it. This is probably the most time-consuming task of the extension process.
In addition, the run_local_test.bash script relies on the fact that "standard" application parameters can be provided to specify the interconnection of said applications to supported device types. If your new networking framework creates port types that can't be specified with the existing options parsed by the testapp executable the latter should be modified, along with some scripts, to support the specification of these new port types.
Other than that, the inclusion of switch start/stop commands to the run_local_test.bash should be the same as described in the previous section.