WARP17 currently supports RAW TCP and HTTP 1.1 application traffic. Even though we are currently working on adding support for more application implementations, external contributions are welcome.
As a future development WARP17 will offer a socket API in order to allow applications to be easily plugged in. Until then any new application must be directly added to the WARP17 code. As an example, a good starting point is the HTTP 1.1 implementation itself.
In general, an application called foo
should implement the following:
-
warp17-app-foo.proto
definition file inapi/
: should contain the application configuration definitions (for clients and servers) and preferably application specific statistics definitions.warp17-app-foo.proto
should be included inwarp17-app.proto
and the application theApp
structure:
message App { required AppProto app_proto = 1; /* Add different App configs below as optionals. */ optional RawClient app_raw_client = 2 [(warp17_union_anon) = true]; optional RawServer app_raw_server = 3 [(warp17_union_anon) = true]; optional HttpClient app_http_client = 4 [(warp17_union_anon) = true]; optional HttpServer app_http_server = 5 [(warp17_union_anon) = true]; optional Imix app_imix = 6 [(warp17_union_anon) = true]; optional Foo app_foo = 7 [(warp17_union_anon) = true]; }
- the application specific statistics should also be added to the
AppStats
definition:
message AppStats { /* The user will do the translation. */ option (warp17_xlate_tpg) = false; optional RawStats as_raw = 1 [(warp17_union_anon) = true]; optional HttpStats as_http = 2 [(warp17_union_anon) = true]; optional ImixStats as_imix = 3 [(warp17_union_anon) = true]; optional FooStats as_foo = 4 [(warp17_union_anon) = true]; }
- a new entry for the application type should be added to the
AppProto
enum inwarp17-common.proto
:
enum AppProto { RAW_CLIENT = 0; RAW_SERVER = 1; HTTP_CLIENT = 2; HTTP_SERVER = 3; IMIX = 4; FOO = 5; APP_PROTO_MAX = 6; }
- the new protocol buffer file (
warp17-app-foo.proto
) should also be added toapi/Makefile.api
:
PROTO-SRCS += warp17-app-raw.proto PROTO-SRCS += warp17-app-http.proto PROTO-SRCS += warp17-app-foo.proto
- the file
Makefile.dpdk
should also be updated to include the new application implementation:
SRCS-y += tpg_test_app.c SRCS-y += tpg_test_http_1_1_app.c SRCS-y += tpg_test_raw_app.c SRCS-y += tpg_test_foo_app.c
- include
warp17-app-foo.proto
intcp_generator.h
:
#include "warp17-app-raw.proto.xlate.h" #include "warp17-app-http.proto.xlate.h" #include "warp17-app-foo.proto.xlate.h"
-
RPC WARP17 to protobuf translation code:
- a new case entry in
tpg_xlate_tpg_union_App
where the application translation function should be called:
case APP_PROTO__HTTP_SERVER: out->app_http_server = rte_zmalloc("TPG_RPC_GEN", sizeof(*out->app_http_server), 0); if (!out->app_http_server) return -ENOMEM; tpg_xlate_tpg_HttpServer(&in->app_http_server, out->app_http_server); break; case APP_PROTO__FOO: out->app_foo = rte_zmalloc("TPG_RPC_GEN", sizeof(*out->app_foo), 0); if (!out->app_foo) return -ENOMEM; tpg_xlate_tpg_Foo(&in->app_foo, out->app_foo); break;
- a new case entry in
tpg_xlate_tpgTestAppStats_by_proto
when translating application statistics:
case APP_PROTO__HTTP_SERVER: out->as_http = rte_zmalloc("TPG_RPC_GEN", sizeof(*out->as_http), 0); if (!out->as_http) return -ENOMEM; err = tpg_xlate_tpg_HttpStats(&in->as_http, out->as_http); if (err) return err; break; case APP_PROTO__FOO: out->as_foo = rte_zmalloc("TPG_RPC_GEN", sizeof(*out->as_foo), 0); if (!out->as_foo) return -ENOMEM; err = tpg_xlate_tpg_FooStats(&in->as_foo, out->as_foo); if (err) return err; break;
- a new case entry in
-
appl/tpg_test_app.h
interface implementation:- application
foo
should be added to theapp_data_t
definition ininc/appl/tpg_test_app.h
. Typefoo_app_t
should be defined in the application headers and should represent a state storage for thefoo
application. The state is part of the L4 control block structures (TCB/UCB).
typedef struct app_data_s { [...] union { raw_app_t ad_raw; http_app_t ad_http; foo_app_t ad_foo; generic_app_t ad_generic; }; } app_data_t;
-
foo
must also provide callback functions corresponding to the callback types defined ininc/appl/tpg_test_app.h
. The callbacks should be added to the callback arrays insrc/appl/tpg_test_app.c
. These functions will be called by the test engine whenever application intervention is required:-
app_default_cfg_cb_t
: should initialize thefoo
application config to default values -
app_validate_cfg_cb_t
: should validate the config corresponding to thefoo
application -
app_print_cfg_cb_t
: should display the part of the configuration corresponding to thefoo
application by using the supplied printer -
app_add_cfg_cb_t
: will be called whenever a test case is added sofoo
initialize everything needed for the test case. -
app_delete_cfg_cb_t
: will be called whenever a test case is deleted sofoo
can cleanup anything it initialized for the test case. -
app_pkts_per_send_cb_t
: will be called when the test case is started to determine how many packets (on average) willfoo
be sending for a single data message -
app_init_cb_t
: will be called whenever a session is initialized and should initialize the application state. -
app_tc_start_stop_cb_t
:foo
should define two callbacks (for test case start and stop). The application should initialize and cleanup any data that is required during the test case (e.g., predefined static data headers) -
app_conn_up_cb_t
: will be called whenever a session has been established -
app_conn_down_cb_t
: will be called whenever a session closed ( either because the underlying connection went down or because the application itself decided to close the connection) -
app_deliver_cb_t
: will be called whenever there was data received for the application to process. The received data is passed as an mbuf chain. The callback should return the total number of bytes that were consumed. For example, in the case of TCP these bytes will be ACK-ed and removed from the receive window. -
app_send_cb_t
: will be called whenever the test engine can send data on the current connection. The application can decide at any time that it would like to start sending or stop sending data by notifying the test engine through theTEST_NOTIF_APP_CLIENT/SERVER_SEND_STOP/START
notifications. Theapp_send_cb_t
callback should return anmbuf
chain pointing to the data it would like to send. In general, freeing thembuf
upon sending is the job of the TCP/IP stack so the application must make sure that it doesn't continue using the mbuf after passing it to the test engine. NOTE: However, for some applications, in order to avoid building packets every time, the implementation might prefer to reuse data templates (e.g., HTTP requests can be easily prebuilt when the test case is started). In such a situation the application can mark the mbufs as STATIC through theDATA_SET_STATIC
call which will inform the test engine that it shouldn't free the data itself. The application must ensure in such a case that the data itself is never freed during the execution of the test case! -
app_data_sent_cb_t
: will be called to notify the application that (part of) the data was sent. It might happen that not all the data could be sent in one shot so the application should returntrue
if what was sent corresponds to a complete message -
app_stats_add_cb_t
: should aggregate application specific statistics -
app_stats_print_cb_t
: should print application specific statistics using the supplied printer
-
-
the
foo
application can request the test engine to perform operations by sending the following notifications:-
TEST_NOTIF_APP_CLIENT/SERVER_SEND_START
: notifies the test engine that the application would like to send data (when possible) on the current connection -
TEST_NOTIF_APP_CLIENT/SERVER_SEND_STOP
: notifies the test engine that the application has finished sending data (for now) on the current connection -
TEST_NOTIF_APP_CLIENT/SERVER_CLOSE
: notifies the test engine that the application would like to close the connection
-
- application
-
CLI: the
foo
application can define it's own CLI commands using the DPDK cmdline infrastructure. These can be added to a localcli_ctx
which can be registered with the main CLI through a call tocli_add_main_ctx
. -
module initialization: the
foo
application must implement two module init functions:-
foo_init
: should initialize global data to be used by the application (e.g., CLI, statistics storage).foo_init
should be called directly from themain
WARP17 function where all modules are initialized. -
foo_lcore_init
: should initalize per core global data to be used by the application (e.g., per core pointers to the statistics corresponding to the current core).foo_lcore_init
should be called frompkt_receive_loop
where all modules are initialized.
-
-
example config: ideally, applications should also provide some configuration examples which could go to the
examples/
directory. -
.dot file: applications will most likely be implemented as state machines. A
.dot
file describing the state machine should be added to thedot/
directory -
tests: any new application shouldn't break any existing tests and must have it's own tests:
-
a configuration and functionality test file in
ut/test_foo.py
which should try to extensively cover all the code introduced by the application -
one or more scaling test entries (method) in
ut/test_perf.py
(class TestPerf) which should define the desired performance/scalability values.
-
-
commit messages: please make sure that commit messages follow the
.git-commit.template
provided in the repository. In order to enforce this template locally you can execute the following command:
git config commit.template ./.git-commit.template