Session layer refactoring
Major refactoring of the session layer api
- Add attatch api for application binding to the the session layer
- Simplify listen/connect calls
- Update application CLI
- Add transport endpoint to accept callback
- Associate segment manager to application and allow for multiple
binds/connects per app
Additional:
- svm fifo cleanup
- add fifo free, format fns
- add fifo offset enqueue unit test
Change-Id: Id93a65047de61afc2bf3d58c9b544339c02065af
Signed-off-by: Florin Coras <fcoras@cisco.com>
Signed-off-by: Dave Barach <dave@barachs.net>
diff --git a/src/vnet/tcp/builtin_client.c b/src/vnet/tcp/builtin_client.c
index 9e8e156..f8fbf28 100644
--- a/src/vnet/tcp/builtin_client.c
+++ b/src/vnet/tcp/builtin_client.c
@@ -237,8 +237,7 @@
memset (dmp, 0, sizeof (*dmp));
dmp->_vl_msg_id = ntohs (VL_API_DISCONNECT_SESSION);
dmp->client_index = tm->my_client_index;
- dmp->session_index = sp->vpp_session_index;
- dmp->session_thread_index = sp->vpp_session_thread;
+ dmp->handle = sp->vpp_session_handle;
vl_msg_api_send_shmem (tm->vl_input_queue, (u8 *) & dmp);
pool_put (tm->sessions, sp);
}
@@ -253,9 +252,10 @@
static void
vl_api_memclnt_create_reply_t_handler (vl_api_memclnt_create_reply_t * mp)
{
+ vlib_main_t *vm = vlib_get_main ();
tclient_main_t *tm = &tclient_main;
-
tm->my_client_index = mp->index;
+ vlib_process_signal_event (vm, tm->node_index, 1 /* evt */ , 0 /* data */ );
}
static void
@@ -264,7 +264,6 @@
tclient_main_t *tm = &tclient_main;
session_t *session;
u32 session_index;
- u64 key;
i32 retval = /* clib_net_to_host_u32 ( */ mp->retval /*) */ ;
if (retval < 0)
@@ -291,24 +290,24 @@
session->server_rx_fifo->client_session_index = session_index;
session->server_tx_fifo = (svm_fifo_t *) mp->server_tx_fifo;
session->server_tx_fifo->client_session_index = session_index;
-
- session->vpp_session_index = mp->session_index;
- session->vpp_session_thread = mp->session_thread_index;
+ session->vpp_session_handle = mp->handle;
/* Add it to the session lookup table */
- key = (((u64) mp->session_thread_index) << 32) | (u64) mp->session_index;
- hash_set (tm->session_index_by_vpp_handles, key, session_index);
+ hash_set (tm->session_index_by_vpp_handles, mp->handle, session_index);
tm->ready_connections++;
}
-static void
+static int
create_api_loopback (tclient_main_t * tm)
{
+ vlib_main_t *vm = vlib_get_main ();
vl_api_memclnt_create_t _m, *mp = &_m;
extern void vl_api_memclnt_create_t_handler (vl_api_memclnt_create_t *);
api_main_t *am = &api_main;
vl_shmem_hdr_t *shmem_hdr;
+ uword *event_data = 0, event_type;
+ int resolved = 0;
/*
* Create a "loopback" API client connection
@@ -324,6 +323,25 @@
strncpy ((char *) mp->name, "tcp_tester", sizeof (mp->name) - 1);
vl_api_memclnt_create_t_handler (mp);
+
+ /* Wait for reply */
+ tm->node_index = vlib_get_current_process (vm)->node_runtime.node_index;
+ vlib_process_wait_for_event_or_clock (vm, 1.0);
+ event_type = vlib_process_get_events (vm, &event_data);
+ switch (event_type)
+ {
+ case 1:
+ resolved = 1;
+ break;
+ case ~0:
+ /* timed out */
+ break;
+ default:
+ clib_warning ("unknown event_type %d", event_type);
+ }
+ if (!resolved)
+ return -1;
+ return 0;
}
#define foreach_tclient_static_api_msg \
@@ -333,17 +351,7 @@
static clib_error_t *
tclient_api_hookup (vlib_main_t * vm)
{
- tclient_main_t *tm = &tclient_main;
vl_msg_api_msg_config_t _c, *c = &_c;
- int i;
-
- /* Init test data */
- vec_validate (tm->connect_test_data, 64 * 1024 - 1);
- for (i = 0; i < vec_len (tm->connect_test_data); i++)
- tm->connect_test_data[i] = i & 0xff;
-
- tm->session_index_by_vpp_handles = hash_create (0, sizeof (uword));
- vec_validate (tm->rx_buf, vec_len (tm->connect_test_data) - 1);
/* Hook up client-side static APIs to our handlers */
#define _(N,n) do { \
@@ -365,18 +373,105 @@
return 0;
}
-VLIB_API_INIT_FUNCTION (tclient_api_hookup);
+static int
+tcp_test_clients_init (vlib_main_t * vm)
+{
+ tclient_main_t *tm = &tclient_main;
+ int i;
+
+ tclient_api_hookup (vm);
+ if (create_api_loopback (tm))
+ return -1;
+
+ /* Init test data */
+ vec_validate (tm->connect_test_data, 64 * 1024 - 1);
+ for (i = 0; i < vec_len (tm->connect_test_data); i++)
+ tm->connect_test_data[i] = i & 0xff;
+
+ tm->session_index_by_vpp_handles = hash_create (0, sizeof (uword));
+ vec_validate (tm->rx_buf, vec_len (tm->connect_test_data) - 1);
+
+ tm->is_init = 1;
+
+ return 0;
+}
+
+static void
+builtin_session_reset_callback (stream_session_t * s)
+{
+ return;
+}
+
+static int
+builtin_session_connected_callback (u32 app_index, u32 api_context,
+ stream_session_t * s, u8 code)
+{
+ return 0;
+}
+
+static int
+builtin_session_create_callback (stream_session_t * s)
+{
+ return 0;
+}
+
+static void
+builtin_session_disconnect_callback (stream_session_t * s)
+{
+ return;
+}
+
+static int
+builtin_server_rx_callback (stream_session_t * s)
+{
+ return 0;
+}
+
+/* *INDENT-OFF* */
+static session_cb_vft_t builtin_clients = {
+ .session_reset_callback = builtin_session_reset_callback,
+ .session_connected_callback = builtin_session_connected_callback,
+ .session_accept_callback = builtin_session_create_callback,
+ .session_disconnect_callback = builtin_session_disconnect_callback,
+ .builtin_server_rx_callback = builtin_server_rx_callback
+};
+/* *INDENT-ON* */
+
+static int
+attach_builtin_test_clients ()
+{
+ vnet_app_attach_args_t _a, *a = &_a;
+ u8 segment_name[128];
+ u32 segment_name_length;
+ u64 options[16];
+
+ segment_name_length = ARRAY_LEN (segment_name);
+
+ memset (a, 0, sizeof (*a));
+ memset (options, 0, sizeof (options));
+
+ a->api_client_index = ~0;
+ a->segment_name = segment_name;
+ a->segment_name_length = segment_name_length;
+ a->session_cb_vft = &builtin_clients;
+
+ options[SESSION_OPTIONS_ACCEPT_COOKIE] = 0x12345678;
+ options[SESSION_OPTIONS_SEGMENT_SIZE] = (2 << 30); /*$$$$ config / arg */
+ a->options = options;
+
+ return vnet_application_attach (a);
+}
static clib_error_t *
test_tcp_clients_command_fn (vlib_main_t * vm,
unformat_input_t * input,
vlib_cli_command_t * cmd)
{
+ tclient_main_t *tm = &tclient_main;
u8 *connect_uri = (u8 *) "tcp://6.0.1.1/1234";
u8 *uri;
- tclient_main_t *tm = &tclient_main;
- int i;
u32 n_clients = 1;
+ int i;
tm->bytes_to_send = 8192;
tm->n_iterations = 1;
@@ -397,14 +492,19 @@
format_unformat_error, input);
}
+ if (tm->is_init == 0)
+ {
+ if (tcp_test_clients_init (vm))
+ return clib_error_return (0, "failed init");
+ }
+
tm->ready_connections = 0;
tm->expected_connections = n_clients;
+
uri = connect_uri;
if (tm->connect_uri)
uri = tm->connect_uri;
- create_api_loopback (tm);
-
#if TCP_BUILTIN_CLIENT_PTHREAD
/* Start a transmit thread */
if (tm->client_thread_handle == 0)
@@ -420,6 +520,7 @@
}
#endif
vnet_session_enable_disable (vm, 1 /* turn on TCP, etc. */ );
+ attach_builtin_test_clients ();
/* Fire off connect requests, in something approaching a normal manner */
for (i = 0; i < n_clients; i++)
@@ -461,6 +562,16 @@
};
/* *INDENT-ON* */
+clib_error_t *
+tcp_test_clients_main_init (vlib_main_t * vm)
+{
+ tclient_main_t *tm = &tclient_main;
+ tm->is_init = 0;
+ return 0;
+}
+
+VLIB_INIT_FUNCTION (tcp_test_clients_main_init);
+
/*
* fd.io coding-style-patch-verification: ON
*
diff --git a/src/vnet/tcp/builtin_client.h b/src/vnet/tcp/builtin_client.h
index 6403030..2bd87c0 100644
--- a/src/vnet/tcp/builtin_client.h
+++ b/src/vnet/tcp/builtin_client.h
@@ -39,8 +39,7 @@
svm_fifo_t *server_rx_fifo;
svm_fifo_t *server_tx_fifo;
- u32 vpp_session_index;
- u32 vpp_session_thread;
+ u64 vpp_session_handle;
} session_t;
typedef struct
@@ -110,6 +109,10 @@
u32 client_bytes_received;
u8 test_return_packets;
+ u8 is_init;
+
+ u32 node_index;
+
/* convenience */
vlib_main_t *vlib_main;
vnet_main_t *vnet_main;
diff --git a/src/vnet/tcp/builtin_server.c b/src/vnet/tcp/builtin_server.c
index 917d4bd..8308e3d 100644
--- a/src/vnet/tcp/builtin_server.c
+++ b/src/vnet/tcp/builtin_server.c
@@ -18,17 +18,46 @@
#include <vnet/session/application.h>
#include <vnet/session/application_interface.h>
+/* define message IDs */
+#include <vpp/api/vpe_msg_enum.h>
+
+/* define message structures */
+#define vl_typedefs
+#include <vpp/api/vpe_all_api_h.h>
+#undef vl_typedefs
+
+/* define generated endian-swappers */
+#define vl_endianfun
+#include <vpp/api/vpe_all_api_h.h>
+#undef vl_endianfun
+
+/* instantiate all the print functions we know about */
+#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
+#define vl_printfun
+#include <vpp/api/vpe_all_api_h.h>
+#undef vl_printfun
+
typedef struct
{
u8 *rx_buf;
unix_shared_memory_queue_t **vpp_queue;
- u32 byte_index;
+ u64 byte_index;
+
+ /* Sever's event queue */
+ unix_shared_memory_queue_t *vl_input_queue;
+
+ /* API client handle */
+ u32 my_client_index;
+
+ u32 app_index;
+
+ /* process node index for evnt scheduling */
+ u32 node_index;
vlib_main_t *vlib_main;
} builtin_server_main_t;
builtin_server_main_t builtin_server_main;
-
int
builtin_session_accept_callback (stream_session_t * s)
{
@@ -45,9 +74,13 @@
void
builtin_session_disconnect_callback (stream_session_t * s)
{
+ builtin_server_main_t *bsm = &builtin_server_main;
+ vnet_disconnect_args_t _a, *a = &_a;
clib_warning ("called...");
- vnet_disconnect_session (s->session_index, s->thread_index);
+ a->handle = stream_session_handle (s);
+ a->app_index = bsm->app_index;
+ vnet_disconnect_session (a);
}
void
@@ -60,7 +93,7 @@
int
-builtin_session_connected_callback (u32 client_index,
+builtin_session_connected_callback (u32 app_index, u32 api_context,
stream_session_t * s, u8 is_fail)
{
clib_warning ("called...");
@@ -91,7 +124,7 @@
{
if (bsm->rx_buf[i] != ((bsm->byte_index + i) & 0xff))
{
- clib_warning ("at %d expected %d got %d", bsm->byte_index + i,
+ clib_warning ("at %lld expected %d got %d", bsm->byte_index + i,
(bsm->byte_index + i) & 0xff, bsm->rx_buf[i]);
}
}
@@ -190,23 +223,66 @@
.session_reset_callback = builtin_session_reset_callback
};
+/* Abuse VPP's input queue */
static int
-server_create (vlib_main_t * vm)
+create_api_loopback (vlib_main_t * vm)
{
- vnet_bind_args_t _a, *a = &_a;
- u64 options[SESSION_OPTIONS_N_OPTIONS];
- char segment_name[128];
- u32 num_threads;
- vlib_thread_main_t *vtm = vlib_get_thread_main ();
+ builtin_server_main_t *bsm = &builtin_server_main;
+ vl_api_memclnt_create_t _m, *mp = &_m;
+ extern void vl_api_memclnt_create_t_handler (vl_api_memclnt_create_t *);
+ api_main_t *am = &api_main;
+ vl_shmem_hdr_t *shmem_hdr;
+ uword *event_data = 0, event_type;
+ int resolved = 0;
- num_threads = 1 /* main thread */ + vtm->n_threads;
- vec_validate (builtin_server_main.vpp_queue, num_threads - 1);
+ /*
+ * Create a "loopback" API client connection
+ * Don't do things like this unless you know what you're doing...
+ */
+
+ shmem_hdr = am->shmem_hdr;
+ bsm->vl_input_queue = shmem_hdr->vl_input_queue;
+ memset (mp, 0, sizeof (*mp));
+ mp->_vl_msg_id = VL_API_MEMCLNT_CREATE;
+ mp->context = 0xFEEDFACE;
+ mp->input_queue = (u64) bsm->vl_input_queue;
+ strncpy ((char *) mp->name, "tcp_test_server", sizeof (mp->name) - 1);
+
+ vl_api_memclnt_create_t_handler (mp);
+
+ /* Wait for reply */
+ bsm->node_index = vlib_get_current_process (vm)->node_runtime.node_index;
+ vlib_process_wait_for_event_or_clock (vm, 1.0);
+ event_type = vlib_process_get_events (vm, &event_data);
+ switch (event_type)
+ {
+ case 1:
+ resolved = 1;
+ break;
+ case ~0:
+ /* timed out */
+ break;
+ default:
+ clib_warning ("unknown event_type %d", event_type);
+ }
+ if (!resolved)
+ return -1;
+
+ return 0;
+}
+
+static int
+server_attach ()
+{
+ builtin_server_main_t *bsm = &builtin_server_main;
+ u8 segment_name[128];
+ u64 options[SESSION_OPTIONS_N_OPTIONS];
+ vnet_app_attach_args_t _a, *a = &_a;
memset (a, 0, sizeof (*a));
memset (options, 0, sizeof (options));
- a->uri = "tcp://0.0.0.0/1234";
- a->api_client_index = ~0;
+ a->api_client_index = bsm->my_client_index;
a->session_cb_vft = &builtin_session_cb_vft;
a->options = options;
a->options[SESSION_OPTIONS_SEGMENT_SIZE] = 128 << 20;
@@ -215,9 +291,94 @@
a->segment_name = segment_name;
a->segment_name_length = ARRAY_LEN (segment_name);
+ if (vnet_application_attach (a))
+ {
+ clib_warning ("failed to attach server");
+ return -1;
+ }
+ bsm->app_index = a->app_index;
+ return 0;
+}
+
+static int
+server_listen ()
+{
+ builtin_server_main_t *bsm = &builtin_server_main;
+ vnet_bind_args_t _a, *a = &_a;
+ memset (a, 0, sizeof (*a));
+ a->app_index = bsm->app_index;
+ a->uri = "tcp://0.0.0.0/1234";
return vnet_bind_uri (a);
}
+static int
+server_create (vlib_main_t * vm)
+{
+ builtin_server_main_t *bsm = &builtin_server_main;
+ u32 num_threads;
+ vlib_thread_main_t *vtm = vlib_get_thread_main ();
+
+ if (bsm->my_client_index == (u32) ~ 0)
+ {
+ if (create_api_loopback (vm))
+ return -1;
+ }
+
+ num_threads = 1 /* main thread */ + vtm->n_threads;
+ vec_validate (builtin_server_main.vpp_queue, num_threads - 1);
+
+ if (server_attach ())
+ {
+ clib_warning ("failed to attach server");
+ return -1;
+ }
+ if (server_listen ())
+ {
+ clib_warning ("failed to start listening");
+ return -1;
+ }
+ return 0;
+}
+
+/* Get our api client index */
+static void
+vl_api_memclnt_create_reply_t_handler (vl_api_memclnt_create_reply_t * mp)
+{
+ vlib_main_t *vm = vlib_get_main ();
+ builtin_server_main_t *bsm = &builtin_server_main;
+ bsm->my_client_index = mp->index;
+ vlib_process_signal_event (vm, bsm->node_index, 1 /* evt */ ,
+ 0 /* data */ );
+}
+
+#define foreach_tcp_builtin_server_api_msg \
+_(MEMCLNT_CREATE_REPLY, memclnt_create_reply) \
+
+static clib_error_t *
+tcp_builtin_server_api_hookup (vlib_main_t * vm)
+{
+ vl_msg_api_msg_config_t _c, *c = &_c;
+
+ /* Hook up client-side static APIs to our handlers */
+#define _(N,n) do { \
+ c->id = VL_API_##N; \
+ c->name = #n; \
+ c->handler = vl_api_##n##_t_handler; \
+ c->cleanup = vl_noop_handler; \
+ c->endian = vl_api_##n##_t_endian; \
+ c->print = vl_api_##n##_t_print; \
+ c->size = sizeof(vl_api_##n##_t); \
+ c->traced = 1; /* trace, so these msgs print */ \
+ c->replay = 0; /* don't replay client create/delete msgs */ \
+ c->message_bounce = 0; /* don't bounce this message */ \
+ vl_msg_api_config(c);} while (0);
+
+ foreach_tcp_builtin_server_api_msg;
+#undef _
+
+ return 0;
+}
+
static clib_error_t *
server_create_command_fn (vlib_main_t * vm,
unformat_input_t * input, vlib_cli_command_t * cmd)
@@ -234,6 +395,7 @@
}
#endif
+ tcp_builtin_server_api_hookup (vm);
vnet_session_enable_disable (vm, 1 /* turn on TCP, etc. */ );
rv = server_create (vm);
switch (rv)
@@ -249,12 +411,22 @@
/* *INDENT-OFF* */
VLIB_CLI_COMMAND (server_create_command, static) =
{
- .path = "test server",
- .short_help = "test server",
+ .path = "test tcp server",
+ .short_help = "test tcp server",
.function = server_create_command_fn,
};
/* *INDENT-ON* */
+clib_error_t *
+builtin_tcp_server_main_init (vlib_main_t * vm)
+{
+ builtin_server_main_t *bsm = &builtin_server_main;
+ bsm->my_client_index = ~0;
+ return 0;
+}
+
+VLIB_INIT_FUNCTION (builtin_tcp_server_main_init);
+
/*
* fd.io coding-style-patch-verification: ON
*
diff --git a/src/vnet/tcp/tcp.c b/src/vnet/tcp/tcp.c
index b6c3482..a0c66b9 100644
--- a/src/vnet/tcp/tcp.c
+++ b/src/vnet/tcp/tcp.c
@@ -34,14 +34,19 @@
listener->c_lcl_port = clib_host_to_net_u16 (port_host_byte_order);
if (is_ip4)
- listener->c_lcl_ip4.as_u32 = ip->ip4.as_u32;
+ {
+ listener->c_lcl_ip4.as_u32 = ip->ip4.as_u32;
+ listener->c_is_ip4 = 1;
+ listener->c_proto = SESSION_TYPE_IP4_TCP;
+ }
else
- clib_memcpy (&listener->c_lcl_ip6, &ip->ip6, sizeof (ip6_address_t));
+ {
+ clib_memcpy (&listener->c_lcl_ip6, &ip->ip6, sizeof (ip6_address_t));
+ listener->c_proto = SESSION_TYPE_IP6_TCP;
+ }
listener->c_s_index = session_index;
- listener->c_proto = SESSION_TYPE_IP4_TCP;
listener->state = TCP_STATE_LISTEN;
- listener->c_is_ip4 = 1;
tcp_connection_timers_init (listener);
@@ -62,7 +67,6 @@
u16 port_host_byte_order)
{
return tcp_connection_bind (session_index, ip, port_host_byte_order, 0);
-
}
static void
@@ -397,6 +401,7 @@
tc->c_lcl_port = clib_host_to_net_u16 (lcl_port);
tc->c_c_index = tc - tm->half_open_connections;
tc->c_is_ip4 = is_ip4;
+ tc->c_proto = is_ip4 ? SESSION_TYPE_IP4_TCP : SESSION_TYPE_IP6_TCP;
/* The other connection vars will be initialized after SYN ACK */
tcp_connection_timers_init (tc);
@@ -518,7 +523,10 @@
tcp_connection_t *tc;
tc = tcp_connection_get (tci, thread_index);
- return format (s, "%U", format_tcp_connection, tc);
+ if (tc)
+ return format (s, "%U", format_tcp_connection, tc);
+ else
+ return format (s, "empty");
}
u8 *
diff --git a/src/vnet/tcp/tcp.h b/src/vnet/tcp/tcp.h
index 2f5da10..93f3245 100644
--- a/src/vnet/tcp/tcp.h
+++ b/src/vnet/tcp/tcp.h
@@ -100,8 +100,6 @@
#define TCP_RTO_SYN_RETRIES 3 /* SYN retries without doubling RTO */
#define TCP_RTO_INIT 1 * THZ /* Initial retransmit timer */
-void tcp_update_time (f64 now, u32 thread_index);
-
/** TCP connection flags */
#define foreach_tcp_connection_flag \
_(SNDACK, "Send ACK") \
@@ -481,6 +479,13 @@
return clib_cpu_time_now () * tcp_main.tstamp_ticks_per_clock;
}
+always_inline void
+tcp_update_time (f64 now, u32 thread_index)
+{
+ tw_timer_expire_timers_16t_2w_512sl (&tcp_main.timer_wheels[thread_index],
+ now);
+}
+
u32 tcp_push_header (transport_connection_t * tconn, vlib_buffer_t * b);
u32
diff --git a/src/vnet/tcp/tcp_input.c b/src/vnet/tcp/tcp_input.c
index 7e9fa47..ae1f92d 100644
--- a/src/vnet/tcp/tcp_input.c
+++ b/src/vnet/tcp/tcp_input.c
@@ -1841,6 +1841,7 @@
case TCP_STATE_ESTABLISHED:
case TCP_STATE_FIN_WAIT_1:
case TCP_STATE_FIN_WAIT_2:
+ vlib_buffer_advance (b0, n_advance_bytes0);
error0 = tcp_segment_rcv (tm, tc0, b0, n_data_bytes0, &next0);
break;
case TCP_STATE_CLOSE_WAIT:
@@ -2410,12 +2411,6 @@
/* *INDENT-ON* */
VLIB_NODE_FUNCTION_MULTIARCH (tcp6_input_node, tcp6_input);
-void
-tcp_update_time (f64 now, u32 thread_index)
-{
- tcp_main_t *tm = vnet_get_tcp_main ();
- tw_timer_expire_timers_16t_2w_512sl (&tm->timer_wheels[thread_index], now);
-}
static void
tcp_dispatch_table_init (tcp_main_t * tm)
diff --git a/src/vnet/tcp/tcp_test.c b/src/vnet/tcp/tcp_test.c
index 0725bb0..3dbbdf6 100644
--- a/src/vnet/tcp/tcp_test.c
+++ b/src/vnet/tcp/tcp_test.c
@@ -12,7 +12,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
#include <vnet/tcp/tcp.h>
#define TCP_TEST_I(_cond, _comment, _args...) \
@@ -174,6 +173,118 @@
return 0;
}
+static int
+tcp_test_fifo (vlib_main_t * vm, unformat_input_t * input)
+{
+ svm_fifo_t *f;
+ u32 fifo_size = 1 << 20;
+ u32 *test_data = 0;
+ u32 offset;
+ int i, rv;
+ u32 data_word, test_data_len;
+
+ /* $$$ parse args */
+ test_data_len = fifo_size / sizeof (u32);
+ vec_validate (test_data, test_data_len - 1);
+
+ for (i = 0; i < vec_len (test_data); i++)
+ test_data[i] = i;
+
+ f = svm_fifo_create (fifo_size);
+
+ /* Paint fifo data vector with -1's */
+ memset (f->data, 0xFF, test_data_len);
+
+ /* Enqueue an initial (un-dequeued) chunk */
+ rv = svm_fifo_enqueue_nowait (f, 0 /* pid */ ,
+ sizeof (u32), (u8 *) test_data);
+
+ if (rv != sizeof (u32))
+ {
+ clib_warning ("enqueue returned %d", rv);
+ goto out;
+ }
+
+ /*
+ * Create 3 chunks in the future. The offsets are relative
+ * to the current fifo tail
+ */
+ for (i = 0; i < 3; i++)
+ {
+ offset = (2 * i + 1) * sizeof (u32);
+ vlib_cli_output (vm, "add offset %d", offset);
+
+ rv = svm_fifo_enqueue_with_offset
+ (f, 0 /* pid */ , offset, sizeof (u32),
+ (u8 *) (test_data + ((offset + sizeof (u32)) / sizeof (u32))));
+
+ if (rv)
+ {
+ clib_warning ("enqueue returned %d", rv);
+ goto out;
+ }
+ }
+
+ /* Paint missing data backwards */
+ for (i = 3; i > 0; i--)
+ {
+ offset = (2 * i + 0) * sizeof (u32);
+
+ vlib_cli_output (vm, "add offset %d", offset);
+
+ rv = svm_fifo_enqueue_with_offset
+ (f, 0 /* pid */ , offset, sizeof (u32),
+ (u8 *) (test_data + ((offset + sizeof (u32)) / sizeof (u32))));
+
+ if (rv)
+ {
+ clib_warning ("enqueue returned %d", rv);
+ goto out;
+ }
+ }
+
+ vlib_cli_output (vm, "fifo before missing link: %U",
+ format_svm_fifo, f, 1 /* verbose */ );
+
+ /* Enqueue the missing u32 */
+ rv = svm_fifo_enqueue_nowait (f, 0 /* pid */ ,
+ sizeof (u32), (u8 *) (test_data + 1));
+ if (rv != 7 * sizeof (u32))
+ {
+ clib_warning ("enqueue returned %d", rv);
+ goto out;
+ }
+
+ vlib_cli_output (vm, "fifo after missing link: %U",
+ format_svm_fifo, f, 1 /* verbose */ );
+
+ /* Collect results */
+ for (i = 0; i < 7; i++)
+ {
+ rv = svm_fifo_dequeue_nowait (f, 0 /* pid */ , sizeof (u32),
+ (u8 *) & data_word);
+ if (rv != sizeof (u32))
+ {
+ clib_warning ("dequeue returned %d", rv);
+ goto out;
+ }
+ if (data_word != test_data[i])
+ {
+ clib_warning ("recovered data %d not %d", data_word, test_data[i]);
+ goto out;
+ }
+ }
+
+ clib_warning ("test complete...");
+
+out:
+ svm_fifo_free (f);
+ vec_free (test_data);
+ return 0;
+}
+
+
+
static clib_error_t *
tcp_test (vlib_main_t * vm,
unformat_input_t * input, vlib_cli_command_t * cmd_arg)
@@ -186,6 +297,10 @@
{
res = tcp_test_sack ();
}
+ else if (unformat (input, "fifo"))
+ {
+ res = tcp_test_fifo (vm, input);
+ }
else
{
return clib_error_return (0, "unknown input `%U'",
@@ -203,10 +318,16 @@
}
}
+/* *INDENT-OFF* */
VLIB_CLI_COMMAND (tcp_test_command, static) =
{
-.path = "test tcp",.short_help = "internal tcp unit tests",.function =
- tcp_test,};
+ .path = "test tcp",
+ .short_help = "internal tcp unit tests",
+ .function = tcp_test,
+};
+/* *INDENT-ON* */
+
+
/*
* fd.io coding-style-patch-verification: ON
*