session: move builtin apps to their own folder

This consolidates builtin apps under session-apps folder. It also
removes duplicate builtin echo server/client implementations.

Change-Id: I75ed879399c5aa9b75b1eb38b33aedf69dd8df3f
Signed-off-by: Florin Coras <fcoras@cisco.com>
diff --git a/src/vnet.am b/src/vnet.am
index 52b4329..7eb4159 100644
--- a/src/vnet.am
+++ b/src/vnet.am
@@ -504,10 +504,6 @@
  vnet/tcp/tcp_output.c				\
  vnet/tcp/tcp_input.c				\
  vnet/tcp/tcp_newreno.c				\
- vnet/tcp/builtin_client.c			\
- vnet/tcp/builtin_server.c			\
- vnet/tcp/builtin_http_server.c			\
- vnet/tcp/builtin_proxy.c			\
  vnet/tcp/tcp_test.c				\
  vnet/tcp/tcp.c
 
@@ -526,7 +522,6 @@
 libvnet_la_SOURCES +=				\
  vnet/udp/udp.c					\
  vnet/udp/udp_input.c				\
- vnet/udp/builtin_server.c			\
  vnet/udp/udp_format.c				\
  vnet/udp/udp_local.c				\
  vnet/udp/udp_pg.c				\
@@ -550,16 +545,13 @@
   vnet/sctp/sctp_pg.c				\
   vnet/sctp/sctp_input.c			\
   vnet/sctp/sctp_output.c			\
-  vnet/sctp/sctp_format.c			\
-  vnet/sctp/builtin_server.c			\
-  vnet/sctp/builtin_client.c
+  vnet/sctp/sctp_format.c
 
 nobase_include_HEADERS +=			\
   vnet/sctp/sctp_error.def                    	\
   vnet/sctp/sctp_packet.h			\
   vnet/sctp/sctp_timer.h			\
-  vnet/sctp/sctp.h				\
-  vnet/sctp/builtin_client.h
+  vnet/sctp/sctp.h
 
 ########################################
 # Tunnel protocol: gre
@@ -964,6 +956,20 @@
 API_FILES += vnet/session/session.api
 
 ########################################
+# session layer applications
+########################################
+
+libvnet_la_SOURCES +=				\
+  vnet/session-apps/echo_client.c		\
+  vnet/session-apps/echo_server.c		\
+  vnet/session-apps/http_server.c		\
+  vnet/session-apps/proxy.c
+
+nobase_include_HEADERS +=			\
+  vnet/session-apps/echo_client.h		\
+  vnet/session-apps/proxy.h
+
+########################################
 # Linux packet interface
 ########################################
 
diff --git a/src/vnet/sctp/builtin_client.c b/src/vnet/sctp/builtin_client.c
deleted file mode 100644
index 12f0532..0000000
--- a/src/vnet/sctp/builtin_client.c
+++ /dev/null
@@ -1,829 +0,0 @@
-/*
- * Copyright (c) 2018 SUSE LLC.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include <vnet/vnet.h>
-#include <vnet/plugin/plugin.h>
-#include <vnet/sctp/builtin_client.h>
-
-#include <vlibapi/api.h>
-#include <vlibmemory/api.h>
-#include <vpp/app/version.h>
-
-tclient_main_t tclient_main;
-
-#define SCTP_BUILTIN_CLIENT_DBG (0)
-
-static void
-signal_evt_to_cli_i (int *code)
-{
-  tclient_main_t *tm = &tclient_main;
-  ASSERT (vlib_get_thread_index () == 0);
-  vlib_process_signal_event (tm->vlib_main, tm->cli_node_index, *code, 0);
-}
-
-static void
-signal_evt_to_cli (int code)
-{
-  if (vlib_get_thread_index () != 0)
-    vl_api_rpc_call_main_thread (signal_evt_to_cli_i, (u8 *) & code,
-				 sizeof (code));
-  else
-    signal_evt_to_cli_i (&code);
-}
-
-static void
-send_test_chunk (tclient_main_t * tm, session_t * s)
-{
-  u8 *test_data = tm->connect_test_data;
-  int test_buf_offset;
-  u32 bytes_this_chunk;
-  session_fifo_event_t evt;
-  svm_fifo_t *txf;
-  int rv;
-
-  ASSERT (vec_len (test_data) > 0);
-
-  test_buf_offset = s->bytes_sent % vec_len (test_data);
-  bytes_this_chunk = vec_len (test_data) - test_buf_offset;
-  bytes_this_chunk = bytes_this_chunk < s->bytes_to_send
-    ? bytes_this_chunk : s->bytes_to_send;
-
-  txf = s->server_tx_fifo;
-  rv = svm_fifo_enqueue_nowait (txf, bytes_this_chunk,
-				test_data + test_buf_offset);
-
-  /* If we managed to enqueue data... */
-  if (rv > 0)
-    {
-      /* Account for it... */
-      s->bytes_to_send -= rv;
-      s->bytes_sent += rv;
-
-      if (SCTP_BUILTIN_CLIENT_DBG)
-	{
-          /* *INDENT-OFF* */
-          ELOG_TYPE_DECLARE (e) =
-            {
-              .format = "tx-enq: xfer %d bytes, sent %u remain %u",
-              .format_args = "i4i4i4",
-            };
-          /* *INDENT-ON* */
-	  struct
-	  {
-	    u32 data[3];
-	  } *ed;
-	  ed = ELOG_DATA (&vlib_global_main.elog_main, e);
-	  ed->data[0] = rv;
-	  ed->data[1] = s->bytes_sent;
-	  ed->data[2] = s->bytes_to_send;
-	}
-
-      /* Poke the session layer */
-      if (svm_fifo_set_event (txf))
-	{
-	  /* Fabricate TX event, send to vpp */
-	  evt.fifo = txf;
-	  evt.event_type = FIFO_EVENT_APP_TX;
-
-	  if (svm_queue_add
-	      (tm->vpp_event_queue[txf->master_thread_index], (u8 *) & evt,
-	       0 /* do wait for mutex */ ))
-	    clib_warning ("could not enqueue event");
-	}
-    }
-}
-
-static void
-receive_test_chunk (tclient_main_t * tm, session_t * s)
-{
-  svm_fifo_t *rx_fifo = s->server_rx_fifo;
-  u32 my_thread_index = vlib_get_thread_index ();
-  int n_read, i;
-
-  /* Allow enqueuing of new event */
-  // svm_fifo_unset_event (rx_fifo);
-
-  if (tm->test_bytes)
-    {
-      n_read = svm_fifo_dequeue_nowait (rx_fifo,
-					vec_len (tm->rx_buf[my_thread_index]),
-					tm->rx_buf[my_thread_index]);
-    }
-  else
-    {
-      n_read = svm_fifo_max_dequeue (rx_fifo);
-      svm_fifo_dequeue_drop (rx_fifo, n_read);
-    }
-
-  if (SCTP_BUILTIN_CLIENT_DBG)
-    clib_warning ("Receiving test chunk; n_read = %d", n_read);
-
-  if (n_read > 0)
-    {
-      if (SCTP_BUILTIN_CLIENT_DBG)
-	{
-          /* *INDENT-OFF* */
-          ELOG_TYPE_DECLARE (e) =
-            {
-              .format = "rx-deq: %d bytes",
-              .format_args = "i4",
-            };
-          /* *INDENT-ON* */
-	  struct
-	  {
-	    u32 data[1];
-	  } *ed;
-	  ed = ELOG_DATA (&vlib_global_main.elog_main, e);
-	  ed->data[0] = n_read;
-	}
-
-      if (tm->test_bytes)
-	{
-	  for (i = 0; i < n_read; i++)
-	    {
-	      if (tm->rx_buf[my_thread_index][i]
-		  != ((s->bytes_received + i) & 0xff))
-		{
-		  clib_warning ("read %d error at byte %lld, 0x%x not 0x%x",
-				n_read, s->bytes_received + i,
-				tm->rx_buf[my_thread_index][i],
-				((s->bytes_received + i) & 0xff));
-		  tm->test_failed = 1;
-		}
-	    }
-	}
-
-      if (s->bytes_to_receive < n_read)
-	{
-	  s->bytes_to_receive = 0;
-	  s->bytes_received += s->bytes_received;
-	}
-      else
-	{
-	  s->bytes_to_receive -= n_read;
-	  s->bytes_received += n_read;
-	}
-    }
-}
-
-static uword
-builtin_client_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
-			vlib_frame_t * frame)
-{
-  tclient_main_t *tm = &tclient_main;
-  int my_thread_index = vlib_get_thread_index ();
-  session_t *sp;
-  int i;
-  int delete_session;
-  u32 *connection_indices;
-  u32 *connections_this_batch;
-  u32 nconnections_this_batch;
-
-  connection_indices = tm->connection_index_by_thread[my_thread_index];
-  connections_this_batch =
-    tm->connections_this_batch_by_thread[my_thread_index];
-
-  if ((tm->run_test == 0) ||
-      ((vec_len (connection_indices) == 0)
-       && vec_len (connections_this_batch) == 0))
-    return 0;
-
-  /* Grab another pile of connections */
-  if (PREDICT_FALSE (vec_len (connections_this_batch) == 0))
-    {
-      nconnections_this_batch =
-	clib_min (tm->connections_per_batch, vec_len (connection_indices));
-
-      ASSERT (nconnections_this_batch > 0);
-      vec_validate (connections_this_batch, nconnections_this_batch - 1);
-      clib_memcpy (connections_this_batch,
-		   connection_indices + vec_len (connection_indices)
-		   - nconnections_this_batch,
-		   nconnections_this_batch * sizeof (u32));
-      _vec_len (connection_indices) -= nconnections_this_batch;
-    }
-
-  if (PREDICT_FALSE (tm->prev_conns != tm->connections_per_batch
-		     && tm->prev_conns == vec_len (connections_this_batch)))
-    {
-      tm->repeats++;
-      tm->prev_conns = vec_len (connections_this_batch);
-      if (tm->repeats == 500000)
-	{
-	  clib_warning ("stuck clients");
-	}
-    }
-  else
-    {
-      tm->prev_conns = vec_len (connections_this_batch);
-      tm->repeats = 0;
-    }
-
-  for (i = 0; i < vec_len (connections_this_batch); i++)
-    {
-      delete_session = 1;
-
-      sp = pool_elt_at_index (tm->sessions, connections_this_batch[i]);
-
-      if (sp->bytes_to_send > 0)
-	{
-	  send_test_chunk (tm, sp);
-	  delete_session = 0;
-	}
-
-      if (sp->bytes_to_receive > 0)
-	{
-	  receive_test_chunk (tm, sp);
-	  delete_session = 0;
-	}
-      if (PREDICT_FALSE (delete_session == 1))
-	{
-	  u32 index, thread_index;
-	  stream_session_t *s;
-
-	  __sync_fetch_and_add (&tm->tx_total, sp->bytes_sent);
-	  __sync_fetch_and_add (&tm->rx_total, sp->bytes_received);
-
-	  session_parse_handle (sp->vpp_session_handle,
-				&index, &thread_index);
-	  s = session_get_if_valid (index, thread_index);
-
-	  if (s)
-	    {
-	      vnet_disconnect_args_t _a, *a = &_a;
-	      a->handle = session_handle (s);
-	      a->app_index = tm->app_index;
-	      vnet_disconnect_session (a);
-
-	      vec_delete (connections_this_batch, 1, i);
-	      i--;
-	      __sync_fetch_and_add (&tm->ready_connections, -1);
-	    }
-	  else
-	    clib_warning ("session AWOL?");
-
-	  /* Kick the debug CLI process */
-	  if (tm->ready_connections == 0)
-	    {
-	      signal_evt_to_cli (2);
-	    }
-	}
-    }
-
-  tm->connection_index_by_thread[my_thread_index] = connection_indices;
-  tm->connections_this_batch_by_thread[my_thread_index] =
-    connections_this_batch;
-  return 0;
-}
-
-/* *INDENT-OFF* */
-VLIB_REGISTER_NODE (builtin_sctp_client_node) =
-{
-  .function = builtin_client_node_fn,
-  .name = "builtin-sctp-client",
-  .type = VLIB_NODE_TYPE_INPUT,
-  .state = VLIB_NODE_STATE_DISABLED,
-};
-/* *INDENT-ON* */
-
-static int
-create_api_loopback (tclient_main_t * tm)
-{
-  api_main_t *am = &api_main;
-  vl_shmem_hdr_t *shmem_hdr;
-
-  shmem_hdr = am->shmem_hdr;
-  tm->vl_input_queue = shmem_hdr->vl_input_queue;
-  tm->my_client_index =
-    vl_api_memclnt_create_internal ("sctp_test_client", tm->vl_input_queue);
-  return 0;
-}
-
-static int
-sctp_test_clients_init (vlib_main_t * vm)
-{
-  tclient_main_t *tm = &tclient_main;
-  vlib_thread_main_t *vtm = vlib_get_thread_main ();
-  u32 num_threads;
-  int i;
-
-  if (create_api_loopback (tm))
-    return -1;
-
-  num_threads = 1 /* main thread */  + vtm->n_threads;
-
-  /* Init test data. Big buffer */
-  vec_validate (tm->connect_test_data, 1024 * 1024 - 1);
-  for (i = 0; i < vec_len (tm->connect_test_data); i++)
-    tm->connect_test_data[i] = i & 0xff;
-
-  vec_validate (tm->rx_buf, num_threads - 1);
-  for (i = 0; i < num_threads; i++)
-    vec_validate (tm->rx_buf[i], vec_len (tm->connect_test_data) - 1);
-
-  tm->is_init = 1;
-
-  vec_validate (tm->connection_index_by_thread, vtm->n_vlib_mains);
-  vec_validate (tm->connections_this_batch_by_thread, vtm->n_vlib_mains);
-  vec_validate (tm->vpp_event_queue, vtm->n_vlib_mains);
-
-  return 0;
-}
-
-static int
-builtin_session_connected_callback (u32 app_index, u32 api_context,
-				    stream_session_t * s, u8 is_fail)
-{
-  tclient_main_t *tm = &tclient_main;
-  session_t *session;
-  u32 session_index;
-  u8 thread_index = vlib_get_thread_index ();
-
-  if (is_fail)
-    {
-      clib_warning ("connection %d failed!", api_context);
-      signal_evt_to_cli (-1);
-      return 0;
-    }
-
-  ASSERT (s->thread_index == thread_index);
-
-  if (!tm->vpp_event_queue[thread_index])
-    tm->vpp_event_queue[thread_index] =
-      session_manager_get_vpp_event_queue (thread_index);
-
-  /*
-   * Setup session
-   */
-  clib_spinlock_lock_if_init (&tm->sessions_lock);
-  pool_get (tm->sessions, session);
-  clib_spinlock_unlock_if_init (&tm->sessions_lock);
-
-  memset (session, 0, sizeof (*session));
-  session_index = session - tm->sessions;
-  session->bytes_to_send = tm->bytes_to_send;
-  session->bytes_to_receive = tm->no_return ? 0ULL : tm->bytes_to_send;
-  session->server_rx_fifo = s->server_rx_fifo;
-  session->server_rx_fifo->client_session_index = session_index;
-  session->server_tx_fifo = s->server_tx_fifo;
-  session->server_tx_fifo->client_session_index = session_index;
-  session->vpp_session_handle = session_handle (s);
-
-  vec_add1 (tm->connection_index_by_thread[thread_index], session_index);
-  __sync_fetch_and_add (&tm->ready_connections, 1);
-  if (tm->ready_connections == tm->expected_connections)
-    {
-      tm->run_test = 1;
-      /* Signal the CLI process that the action is starting... */
-      signal_evt_to_cli (1);
-    }
-
-  return 0;
-}
-
-static void
-builtin_session_reset_callback (stream_session_t * s)
-{
-  if (s->session_state == SESSION_STATE_READY)
-    clib_warning ("Reset active connection %U", format_stream_session, s, 2);
-  stream_session_cleanup (s);
-  return;
-}
-
-static int
-builtin_session_create_callback (stream_session_t * s)
-{
-  return 0;
-}
-
-static void
-builtin_session_disconnect_callback (stream_session_t * s)
-{
-  tclient_main_t *tm = &tclient_main;
-  vnet_disconnect_args_t _a, *a = &_a;
-  a->handle = session_handle (s);
-  a->app_index = tm->app_index;
-  vnet_disconnect_session (a);
-  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 clib_error_t *
-attach_builtin_test_clients_app (u8 * appns_id, u64 appns_flags,
-				 u64 appns_secret)
-{
-  u32 prealloc_fifos, segment_size = 2 << 20;
-  tclient_main_t *tm = &tclient_main;
-  vnet_app_attach_args_t _a, *a = &_a;
-  u64 options[16];
-  clib_error_t *error = 0;
-
-  memset (a, 0, sizeof (*a));
-  memset (options, 0, sizeof (options));
-
-  a->api_client_index = tm->my_client_index;
-  a->session_cb_vft = &builtin_clients;
-
-  prealloc_fifos = tm->prealloc_fifos ? tm->expected_connections : 1;
-
-  if (tm->private_segment_size)
-    segment_size = tm->private_segment_size;
-
-  options[APP_OPTIONS_ACCEPT_COOKIE] = 0x12345678;
-  options[APP_OPTIONS_SEGMENT_SIZE] = segment_size;
-  options[APP_OPTIONS_RX_FIFO_SIZE] = tm->fifo_size;
-  options[APP_OPTIONS_TX_FIFO_SIZE] = tm->fifo_size;
-  options[APP_OPTIONS_PRIVATE_SEGMENT_COUNT] = tm->private_segment_count;
-  options[APP_OPTIONS_PREALLOC_FIFO_PAIRS] = prealloc_fifos;
-
-  options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
-  if (appns_id)
-    {
-      options[APP_OPTIONS_FLAGS] |= appns_flags;
-      options[APP_OPTIONS_NAMESPACE_SECRET] = appns_secret;
-    }
-  a->options = options;
-  a->namespace_id = appns_id;
-
-  if ((error = vnet_application_attach (a)))
-    return error;
-
-  tm->app_index = a->app_index;
-  return 0;
-}
-
-static void *
-tclient_thread_fn (void *arg)
-{
-  return 0;
-}
-
-/** Start a transmit thread */
-int
-start_tx_pthread_sctp (tclient_main_t * tm)
-{
-  if (tm->client_thread_handle == 0)
-    {
-      int rv = pthread_create (&tm->client_thread_handle,
-			       NULL /*attr */ ,
-			       tclient_thread_fn, 0);
-      if (rv)
-	{
-	  tm->client_thread_handle = 0;
-	  return -1;
-	}
-    }
-  return 0;
-}
-
-clib_error_t *
-clients_connect_sctp (vlib_main_t * vm, u8 * uri, u32 n_clients)
-{
-  tclient_main_t *tm = &tclient_main;
-  vnet_connect_args_t _a, *a = &_a;
-  clib_error_t *error = 0;
-  int i;
-  for (i = 0; i < n_clients; i++)
-    {
-      memset (a, 0, sizeof (*a));
-
-      a->uri = (char *) uri;
-      a->api_context = i;
-      a->app_index = tm->app_index;
-      a->mp = 0;
-
-      if ((error = vnet_connect_uri (a)))
-	return error;
-
-
-      /* Crude pacing for call setups  */
-      if ((i % 4) == 0)
-	vlib_process_suspend (vm, 10e-6);
-      ASSERT (i + 1 >= tm->ready_connections);
-      while (i + 1 - tm->ready_connections > 1000)
-	{
-	  vlib_process_suspend (vm, 100e-6);
-	}
-    }
-  return 0;
-}
-
-#define CLI_OUTPUT(_fmt, _args...) 			\
-  if (!tm->no_output)  					\
-    vlib_cli_output(vm, _fmt, ##_args)
-
-static clib_error_t *
-test_sctp_clients_command_fn (vlib_main_t * vm,
-			      unformat_input_t * input,
-			      vlib_cli_command_t * cmd)
-{
-  tclient_main_t *tm = &tclient_main;
-  vlib_thread_main_t *thread_main = vlib_get_thread_main ();
-  uword *event_data = 0, event_type;
-  u8 *default_connect_uri = (u8 *) "sctp://6.0.1.1/1234", *uri, *appns_id = 0;
-  u64 tmp, total_bytes, appns_flags = 0, appns_secret = 0;
-  f64 test_timeout = 20.0, syn_timeout = 20.0, delta;
-  f64 time_before_connects;
-  u32 n_clients = 1;
-  int preallocate_sessions = 0;
-  char *transfer_type;
-  clib_error_t *error = 0;
-  int i;
-
-  tm->bytes_to_send = 8192;
-  tm->no_return = 0;
-  tm->fifo_size = 64 << 10;
-  tm->connections_per_batch = 1000;
-  tm->private_segment_count = 0;
-  tm->private_segment_size = 0;
-  tm->no_output = 0;
-  tm->test_bytes = 0;
-  tm->test_failed = 0;
-  tm->vlib_main = vm;
-  if (thread_main->n_vlib_mains > 1)
-    clib_spinlock_init (&tm->sessions_lock);
-  vec_free (tm->connect_uri);
-
-  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
-    {
-      if (unformat (input, "nclients %d", &n_clients))
-	;
-      else if (unformat (input, "mbytes %lld", &tmp))
-	tm->bytes_to_send = tmp << 20;
-      else if (unformat (input, "gbytes %lld", &tmp))
-	tm->bytes_to_send = tmp << 30;
-      else if (unformat (input, "bytes %lld", &tm->bytes_to_send))
-	;
-      else if (unformat (input, "uri %s", &tm->connect_uri))
-	;
-      else if (unformat (input, "test-timeout %f", &test_timeout))
-	;
-      else if (unformat (input, "syn-timeout %f", &syn_timeout))
-	;
-      else if (unformat (input, "no-return"))
-	tm->no_return = 1;
-      else if (unformat (input, "fifo-size %d", &tm->fifo_size))
-	tm->fifo_size <<= 10;
-      else if (unformat (input, "private-segment-count %d",
-			 &tm->private_segment_count))
-	;
-      else if (unformat (input, "private-segment-size %U",
-			 unformat_memory_size, &tmp))
-	{
-	  if (tmp >= 0x100000000ULL)
-	    return clib_error_return
-	      (0, "private segment size %lld (%llu) too large", tmp, tmp);
-	  tm->private_segment_size = tmp;
-	}
-      else if (unformat (input, "preallocate-fifos"))
-	tm->prealloc_fifos = 1;
-      else if (unformat (input, "preallocate-sessions"))
-	preallocate_sessions = 1;
-      else
-	if (unformat (input, "client-batch %d", &tm->connections_per_batch))
-	;
-      else if (unformat (input, "appns %_%v%_", &appns_id))
-	;
-      else if (unformat (input, "all-scope"))
-	appns_flags |= (APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE
-			| APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE);
-      else if (unformat (input, "local-scope"))
-	appns_flags = APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
-      else if (unformat (input, "global-scope"))
-	appns_flags = APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
-      else if (unformat (input, "secret %lu", &appns_secret))
-	;
-      else if (unformat (input, "no-output"))
-	tm->no_output = 1;
-      else if (unformat (input, "test-bytes"))
-	tm->test_bytes = 1;
-      else
-	return clib_error_return (0, "unknown input `%U'",
-				  format_unformat_error, input);
-    }
-
-  /* Store cli process node index for signalling */
-  tm->cli_node_index = vlib_get_current_process (vm)->node_runtime.node_index;
-
-  if (tm->is_init == 0)
-    {
-      if (sctp_test_clients_init (vm))
-	return clib_error_return (0, "failed init");
-    }
-
-  tm->ready_connections = 0;
-  tm->expected_connections = n_clients;
-  tm->rx_total = 0;
-  tm->tx_total = 0;
-
-  uri = default_connect_uri;
-  if (tm->connect_uri)
-    uri = tm->connect_uri;
-
-#if SCTP_BUILTIN_CLIENT_PTHREAD
-  start_tx_pthread ();
-#endif
-
-  vlib_worker_thread_barrier_sync (vm);
-  vnet_session_enable_disable (vm, 1 /* turn on SCTP, etc. */ );
-  vlib_worker_thread_barrier_release (vm);
-
-  if (tm->test_client_attached == 0)
-    {
-      if ((error = attach_builtin_test_clients_app (appns_id, appns_flags,
-						    appns_secret)))
-	{
-	  vec_free (appns_id);
-	  clib_error_report (error);
-	  return error;
-	}
-      vec_free (appns_id);
-    }
-  tm->test_client_attached = 1;
-
-  /* Turn on the builtin client input nodes */
-  for (i = 0; i < thread_main->n_vlib_mains; i++)
-    vlib_node_set_state (vlib_mains[i], builtin_sctp_client_node.index,
-			 VLIB_NODE_STATE_POLLING);
-
-  if (preallocate_sessions)
-    {
-      session_t *sp __attribute__ ((unused));
-      for (i = 0; i < n_clients; i++)
-	pool_get (tm->sessions, sp);
-      for (i = 0; i < n_clients; i++)
-	pool_put_index (tm->sessions, i);
-    }
-
-  /* Fire off connect requests */
-  time_before_connects = vlib_time_now (vm);
-  if ((error = clients_connect_sctp (vm, uri, n_clients)))
-    return error;
-
-  /* Park until the sessions come up, or ten seconds elapse... */
-  vlib_process_wait_for_event_or_clock (vm, syn_timeout);
-
-  event_type = vlib_process_get_events (vm, &event_data);
-  switch (event_type)
-    {
-    case ~0:
-      CLI_OUTPUT ("Timeout with only %d sessions active...",
-		  tm->ready_connections);
-      error =
-	clib_error_return (0, "failed: syn timeout (%f) with %d sessions",
-			   syn_timeout, tm->ready_connections);
-      goto cleanup;
-
-    case 1:
-      delta = vlib_time_now (vm) - time_before_connects;
-      if (delta != 0.0)
-	CLI_OUTPUT ("%d three-way handshakes in %.2f seconds %.2f/s",
-		    n_clients, delta, ((f64) n_clients) / delta);
-
-      tm->test_start_time = vlib_time_now (tm->vlib_main);
-      CLI_OUTPUT ("Test started at %.6f", tm->test_start_time);
-      break;
-
-    default:
-      CLI_OUTPUT ("unexpected event(1): %d", event_type);
-      error = clib_error_return (0, "failed: unexpected event(1): %d",
-				 event_type);
-      goto cleanup;
-    }
-
-  /* Now wait for the sessions to finish... */
-  vlib_process_wait_for_event_or_clock (vm, test_timeout);
-  event_type = vlib_process_get_events (vm, &event_data);
-  switch (event_type)
-    {
-    case ~0:
-      CLI_OUTPUT ("Timeout with %d sessions still active...",
-		  tm->ready_connections);
-      error = clib_error_return (0, "failed: timeout with %d sessions",
-				 tm->ready_connections);
-      goto cleanup;
-
-    case 2:
-      tm->test_end_time = vlib_time_now (vm);
-      CLI_OUTPUT ("Test finished at %.6f", tm->test_end_time);
-      break;
-
-    default:
-      CLI_OUTPUT ("unexpected event(2): %d", event_type);
-      error = clib_error_return (0, "failed: unexpected event(2): %d",
-				 event_type);
-      goto cleanup;
-    }
-
-  delta = tm->test_end_time - tm->test_start_time;
-
-  if (delta != 0.0)
-    {
-      total_bytes = (tm->no_return ? tm->tx_total : tm->rx_total);
-      transfer_type = tm->no_return ? "half-duplex" : "full-duplex";
-      CLI_OUTPUT ("%lld bytes (%lld mbytes, %lld gbytes) in %.2f seconds",
-		  total_bytes, total_bytes / (1ULL << 20),
-		  total_bytes / (1ULL << 30), delta);
-      CLI_OUTPUT ("%.2f bytes/second %s", ((f64) total_bytes) / (delta),
-		  transfer_type);
-      CLI_OUTPUT ("%.4f gbit/second %s",
-		  (((f64) total_bytes * 8.0) / delta / 1e9), transfer_type);
-    }
-  else
-    {
-      CLI_OUTPUT ("zero delta-t?");
-      error = clib_error_return (0, "failed: zero delta-t");
-      goto cleanup;
-    }
-
-  if (tm->test_bytes && tm->test_failed)
-    error = clib_error_return (0, "failed: test bytes");
-
-cleanup:
-  tm->run_test = 0;
-  for (i = 0; i < vec_len (tm->connection_index_by_thread); i++)
-    {
-      vec_reset_length (tm->connection_index_by_thread[i]);
-      vec_reset_length (tm->connections_this_batch_by_thread[i]);
-    }
-
-  pool_free (tm->sessions);
-
-  /* Detach the application, so we can use different fifo sizes next time */
-  if (tm->test_client_attached)
-    {
-      vnet_app_detach_args_t _da, *da = &_da;
-      int rv;
-
-      da->app_index = tm->app_index;
-      rv = vnet_application_detach (da);
-      if (rv)
-	{
-	  error = clib_error_return (0, "failed: app detach");
-	  CLI_OUTPUT ("WARNING: app detach failed...");
-	}
-      tm->test_client_attached = 0;
-      tm->app_index = ~0;
-    }
-  if (error)
-    CLI_OUTPUT ("test failed");
-  return error;
-}
-
-/* *INDENT-OFF* */
-VLIB_CLI_COMMAND (test_clients_command, static) =
-{
-  .path = "test sctp clients",
-  .short_help = "test sctp clients [nclients %d] [[m|g]bytes <bytes>] "
-      "[test-timeout <time>][syn-timeout <time>][no-return][fifo-size <size>]"
-      "[private-segment-count <count>][private-segment-size <bytes>[m|g]]"
-      "[preallocate-fifos][preallocate-sessions][client-batch <batch-size>]"
-      "[uri <sctp://ip/port>][test-bytes][no-output]",
-  .function = test_sctp_clients_command_fn,
-  .is_mp_safe = 1,
-};
-/* *INDENT-ON* */
-
-clib_error_t *
-sctp_test_clients_main_init (vlib_main_t * vm)
-{
-  tclient_main_t *tm = &tclient_main;
-  tm->is_init = 0;
-  return 0;
-}
-
-VLIB_INIT_FUNCTION (sctp_test_clients_main_init);
-
-/*
- * fd.io coding-style-patch-verification: ON
- *
- * Local Variables:
- * eval: (c-set-style "gnu")
- * End:
- */
diff --git a/src/vnet/sctp/builtin_client.h b/src/vnet/sctp/builtin_client.h
deleted file mode 100644
index ecf22d8..0000000
--- a/src/vnet/sctp/builtin_client.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (c) 2018 SUSE LLC.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef __included_tclient_h__
-#define __included_tclient_h__
-
-#include <vnet/vnet.h>
-#include <vnet/ip/ip.h>
-#include <vnet/ethernet/ethernet.h>
-
-#include <vppinfra/hash.h>
-#include <vppinfra/error.h>
-#include <svm/queue.h>
-#include <svm/svm_fifo_segment.h>
-#include <vnet/session/session.h>
-#include <vnet/session/application_interface.h>
-
-typedef struct
-{
-  u64 bytes_to_send;
-  u64 bytes_sent;
-  u64 bytes_to_receive;
-  u64 bytes_received;
-
-  svm_fifo_t *server_rx_fifo;
-  svm_fifo_t *server_tx_fifo;
-
-  u64 vpp_session_handle;
-} session_t;
-
-typedef struct
-{
-  /*
-   * Application setup parameters
-   */
-  svm_queue_t *vl_input_queue;		/**< vpe input queue */
-  svm_queue_t **vpp_event_queue;
-
-  u32 cli_node_index;			/**< cli process node index */
-  u32 my_client_index;			/**< loopback API client handle */
-  u32 app_index;			/**< app index after attach */
-
-  /*
-   * Configuration params
-   */
-  u8 *connect_uri;			/**< URI for slave's connect */
-  u64 bytes_to_send;			/**< Bytes to send */
-  u32 configured_segment_size;
-  u32 fifo_size;
-  u32 expected_connections;		/**< Number of clients/connections */
-  u32 connections_per_batch;		/**< Connections to rx/tx at once */
-  u32 private_segment_count;		/**< Number of private fifo segs */
-  u32 private_segment_size;		/**< size of private fifo segs */
-
-  /*
-   * Test state variables
-   */
-  session_t *sessions;			/**< Session pool, shared */
-  clib_spinlock_t sessions_lock;
-  u8 **rx_buf;				/**< intermediate rx buffers */
-  u8 *connect_test_data;		/**< Pre-computed test data */
-  u32 **connection_index_by_thread;
-  u32 **connections_this_batch_by_thread; /**< active connection batch */
-  pthread_t client_thread_handle;
-
-  volatile u32 ready_connections;
-  volatile u32 finished_connections;
-  volatile u64 rx_total;
-  volatile u64 tx_total;
-  volatile int run_test;		/**< Signal start of test */
-
-  f64 test_start_time;
-  f64 test_end_time;
-  u32 prev_conns;
-  u32 repeats;
-  /*
-   * Flags
-   */
-  u8 is_init;
-  u8 test_client_attached;
-  u8 no_return;
-  u8 test_return_packets;
-  int i_am_master;
-  int drop_packets;		/**< drop all packets */
-  u8 prealloc_fifos;		/**< Request fifo preallocation */
-  u8 no_output;
-  u8 test_bytes;
-  u8 test_failed;
-
-  /*
-   * Convenience
-   */
-  vlib_main_t *vlib_main;
-  vnet_main_t *vnet_main;
-  ethernet_main_t *ethernet_main;
-} tclient_main_t;
-
-extern tclient_main_t tclient_main;
-
-vlib_node_registration_t tclient_node;
-
-#endif /* __included_tclient_h__ */
-
-/*
- * fd.io coding-style-patch-verification: ON
- *
- * Local Variables:
- * eval: (c-set-style "gnu")
- * End:
- */
diff --git a/src/vnet/sctp/builtin_server.c b/src/vnet/sctp/builtin_server.c
deleted file mode 100644
index e67c4ab..0000000
--- a/src/vnet/sctp/builtin_server.c
+++ /dev/null
@@ -1,469 +0,0 @@
-/*
- * Copyright (c) 2018 SUSE LLC.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include <vnet/vnet.h>
-#include <vlibmemory/api.h>
-#include <vnet/session/application.h>
-#include <vnet/session/application_interface.h>
-
-typedef struct
-{
-  /*
-   * Server app parameters
-   */
-  svm_queue_t **vpp_queue;
-  svm_queue_t *vl_input_queue;		/**< Sever's event queue */
-
-  u32 app_index;		/**< Server app index */
-  u32 my_client_index;		/**< API client handle */
-  u32 node_index;		/**< process node index for evnt scheduling */
-
-  /*
-   * Config params
-   */
-  u8 no_echo;			/**< Don't echo traffic */
-  u32 fifo_size;			/**< Fifo size */
-  u32 rcv_buffer_size;		/**< Rcv buffer size */
-  u32 prealloc_fifos;		/**< Preallocate fifos */
-  u32 private_segment_count;	/**< Number of private segments  */
-  u32 private_segment_size;	/**< Size of private segments  */
-  char *server_uri;		/**< Server URI */
-
-  /*
-   * Test state
-   */
-  u8 **rx_buf;			/**< Per-thread RX buffer */
-  u64 byte_index;
-  u32 **rx_retries;
-
-  vlib_main_t *vlib_main;
-} builtin_server_main_t;
-
-builtin_server_main_t builtin_server_main;
-
-int
-builtin_sctp_session_accept_callback (stream_session_t * s)
-{
-  builtin_server_main_t *bsm = &builtin_server_main;
-
-  bsm->vpp_queue[s->thread_index] =
-    session_manager_get_vpp_event_queue (s->thread_index);
-  s->session_state = SESSION_STATE_READY;
-  bsm->byte_index = 0;
-  vec_validate (bsm->rx_retries[s->thread_index], s->session_index);
-  bsm->rx_retries[s->thread_index][s->session_index] = 0;
-  return 0;
-}
-
-void
-builtin_sctp_session_disconnect_callback (stream_session_t * s)
-{
-  builtin_server_main_t *bsm = &builtin_server_main;
-  vnet_disconnect_args_t _a, *a = &_a;
-
-  a->handle = session_handle (s);
-  a->app_index = bsm->app_index;
-  vnet_disconnect_session (a);
-}
-
-void
-builtin_sctp_session_reset_callback (stream_session_t * s)
-{
-  clib_warning ("Reset session %U", format_stream_session, s, 2);
-  stream_session_cleanup (s);
-}
-
-
-int
-builtin_sctp_session_connected_callback (u32 app_index, u32 api_context,
-					 stream_session_t * s, u8 is_fail)
-{
-  clib_warning ("called...");
-  return -1;
-}
-
-int
-builtin_sctp_add_segment_callback (u32 client_index,
-				   const ssvm_private_t * fs)
-{
-  clib_warning ("called...");
-  return -1;
-}
-
-int
-builtin_sctp_redirect_connect_callback (u32 client_index, void *mp)
-{
-  clib_warning ("called...");
-  return -1;
-}
-
-void
-test_bytes_sctp (builtin_server_main_t * bsm, int actual_transfer)
-{
-  int i;
-  u32 my_thread_id = vlib_get_thread_index ();
-
-  for (i = 0; i < actual_transfer; i++)
-    {
-      if (bsm->rx_buf[my_thread_id][i] != ((bsm->byte_index + i) & 0xff))
-	{
-	  clib_warning ("at %lld expected %d got %d", bsm->byte_index + i,
-			(bsm->byte_index + i) & 0xff,
-			bsm->rx_buf[my_thread_id][i]);
-	}
-    }
-  bsm->byte_index += actual_transfer;
-}
-
-/*
- * If no-echo, just read the data and be done with it
- */
-int
-builtin_sctp_server_rx_callback_no_echo (stream_session_t * s)
-{
-  builtin_server_main_t *bsm = &builtin_server_main;
-  u32 my_thread_id = vlib_get_thread_index ();
-  int actual_transfer;
-  svm_fifo_t *rx_fifo;
-
-  rx_fifo = s->server_rx_fifo;
-
-  do
-    {
-      actual_transfer =
-	svm_fifo_dequeue_nowait (rx_fifo, bsm->rcv_buffer_size,
-				 bsm->rx_buf[my_thread_id]);
-    }
-  while (actual_transfer > 0);
-  return 0;
-}
-
-int
-builtin_sctp_server_rx_callback (stream_session_t * s)
-{
-  u32 n_written, max_dequeue, max_enqueue, max_transfer;
-  int actual_transfer;
-  svm_fifo_t *tx_fifo, *rx_fifo;
-  builtin_server_main_t *bsm = &builtin_server_main;
-  session_fifo_event_t evt;
-  u32 thread_index = vlib_get_thread_index ();
-
-  ASSERT (s->thread_index == thread_index);
-
-  rx_fifo = s->server_rx_fifo;
-  tx_fifo = s->server_tx_fifo;
-
-  ASSERT (rx_fifo->master_thread_index == thread_index);
-  ASSERT (tx_fifo->master_thread_index == thread_index);
-
-  max_dequeue = svm_fifo_max_dequeue (s->server_rx_fifo);
-  max_enqueue = svm_fifo_max_enqueue (s->server_tx_fifo);
-
-  if (PREDICT_FALSE (max_dequeue == 0))
-    return 0;
-
-  /* Number of bytes we're going to copy */
-  max_transfer = (max_dequeue < max_enqueue) ? max_dequeue : max_enqueue;
-
-  /* No space in tx fifo */
-  if (PREDICT_FALSE (max_transfer == 0))
-    {
-      /* XXX timeout for session that are stuck */
-
-    rx_event:
-      /* Program self-tap to retry */
-      if (svm_fifo_set_event (rx_fifo))
-	{
-	  svm_queue_t *q;
-	  evt.fifo = rx_fifo;
-	  evt.event_type = FIFO_EVENT_BUILTIN_RX;
-
-	  q = bsm->vpp_queue[thread_index];
-	  if (PREDICT_FALSE (q->cursize == q->maxsize))
-	    clib_warning ("out of event queue space");
-	  else if (svm_queue_add (q, (u8 *) & evt, 0))
-	    clib_warning ("failed to enqueue self-tap");
-
-	  if (bsm->rx_retries[thread_index][s->session_index] == 500000)
-	    {
-	      clib_warning ("session stuck: %U", format_stream_session, s, 2);
-	    }
-	  if (bsm->rx_retries[thread_index][s->session_index] < 500001)
-	    bsm->rx_retries[thread_index][s->session_index]++;
-	}
-
-      return 0;
-    }
-
-  _vec_len (bsm->rx_buf[thread_index]) = max_transfer;
-
-  actual_transfer = svm_fifo_dequeue_nowait (rx_fifo, max_transfer,
-					     bsm->rx_buf[thread_index]);
-  ASSERT (actual_transfer == max_transfer);
-
-//  test_bytes (bsm, actual_transfer);
-
-  /*
-   * Echo back
-   */
-
-  n_written = svm_fifo_enqueue_nowait (tx_fifo, actual_transfer,
-				       bsm->rx_buf[thread_index]);
-
-  if (n_written != max_transfer)
-    clib_warning ("short trout!");
-
-  if (svm_fifo_set_event (tx_fifo))
-    {
-      /* Fabricate TX event, send to vpp */
-      evt.fifo = tx_fifo;
-      evt.event_type = FIFO_EVENT_APP_TX;
-
-      if (svm_queue_add (bsm->vpp_queue[s->thread_index],
-			 (u8 *) & evt, 0 /* do wait for mutex */ ))
-	clib_warning ("failed to enqueue tx evt");
-    }
-
-  if (PREDICT_FALSE (n_written < max_dequeue))
-    goto rx_event;
-
-  return 0;
-}
-
-static session_cb_vft_t builtin_session_cb_vft = {
-  .session_accept_callback = builtin_sctp_session_accept_callback,
-  .session_disconnect_callback = builtin_sctp_session_disconnect_callback,
-  .session_connected_callback = builtin_sctp_session_connected_callback,
-  .add_segment_callback = builtin_sctp_add_segment_callback,
-  .redirect_connect_callback = builtin_sctp_redirect_connect_callback,
-  .builtin_server_rx_callback = builtin_sctp_server_rx_callback,
-  .session_reset_callback = builtin_sctp_session_reset_callback
-};
-
-/* Abuse VPP's input queue */
-static int
-create_api_loopback (vlib_main_t * vm)
-{
-  builtin_server_main_t *bsm = &builtin_server_main;
-  api_main_t *am = &api_main;
-  vl_shmem_hdr_t *shmem_hdr;
-
-  shmem_hdr = am->shmem_hdr;
-  bsm->vl_input_queue = shmem_hdr->vl_input_queue;
-  bsm->my_client_index =
-    vl_api_memclnt_create_internal ("sctp_test_server", bsm->vl_input_queue);
-  return 0;
-}
-
-static int
-server_attach (u8 * appns_id, u64 appns_flags, u64 appns_secret)
-{
-  builtin_server_main_t *bsm = &builtin_server_main;
-  u64 options[APP_OPTIONS_N_OPTIONS];
-  vnet_app_attach_args_t _a, *a = &_a;
-  u32 segment_size = 512 << 20;
-
-  memset (a, 0, sizeof (*a));
-  memset (options, 0, sizeof (options));
-
-  if (bsm->no_echo)
-    builtin_session_cb_vft.builtin_server_rx_callback =
-      builtin_sctp_server_rx_callback_no_echo;
-  else
-    builtin_session_cb_vft.builtin_server_rx_callback =
-      builtin_sctp_server_rx_callback;
-
-  if (bsm->private_segment_size)
-    segment_size = bsm->private_segment_size;
-
-  a->api_client_index = bsm->my_client_index;
-  a->session_cb_vft = &builtin_session_cb_vft;
-  a->options = options;
-  a->options[APP_OPTIONS_SEGMENT_SIZE] = segment_size;
-  a->options[APP_OPTIONS_RX_FIFO_SIZE] = bsm->fifo_size;
-  a->options[APP_OPTIONS_TX_FIFO_SIZE] = bsm->fifo_size;
-  a->options[APP_OPTIONS_PRIVATE_SEGMENT_COUNT] = bsm->private_segment_count;
-  a->options[APP_OPTIONS_PREALLOC_FIFO_PAIRS] =
-    bsm->prealloc_fifos ? bsm->prealloc_fifos : 1;
-
-  a->options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
-  if (appns_id)
-    {
-      a->namespace_id = appns_id;
-      a->options[APP_OPTIONS_FLAGS] |= appns_flags;
-      a->options[APP_OPTIONS_NAMESPACE_SECRET] = appns_secret;
-    }
-
-  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 = bsm->server_uri;
-  return vnet_bind_uri (a);
-}
-
-static int
-server_create (vlib_main_t * vm, u8 * appns_id, u64 appns_flags,
-	       u64 appns_secret)
-{
-  builtin_server_main_t *bsm = &builtin_server_main;
-  vlib_thread_main_t *vtm = vlib_get_thread_main ();
-  u32 num_threads;
-  int i;
-
-  if (bsm->my_client_index == (u32) ~ 0)
-    {
-      if (create_api_loopback (vm))
-	{
-	  clib_warning ("failed to create api loopback");
-	  return -1;
-	}
-    }
-
-  num_threads = 1 /* main thread */  + vtm->n_threads;
-  vec_validate (builtin_server_main.vpp_queue, num_threads - 1);
-  vec_validate (bsm->rx_buf, num_threads - 1);
-  vec_validate (bsm->rx_retries, num_threads - 1);
-
-  for (i = 0; i < num_threads; i++)
-    vec_validate (bsm->rx_buf[i], bsm->rcv_buffer_size);
-
-  if (server_attach (appns_id, appns_flags, appns_secret))
-    {
-      clib_warning ("failed to attach server");
-      return -1;
-    }
-  if (server_listen ())
-    {
-      clib_warning ("failed to start listening");
-      return -1;
-    }
-  return 0;
-}
-
-static clib_error_t *
-server_create_command_fn (vlib_main_t * vm, unformat_input_t * input,
-			  vlib_cli_command_t * cmd)
-{
-  builtin_server_main_t *bsm = &builtin_server_main;
-  u8 server_uri_set = 0, *appns_id = 0;
-  u64 tmp, appns_flags = 0, appns_secret = 0;
-  int rv;
-
-  bsm->no_echo = 0;
-  bsm->fifo_size = 64 << 10;
-  bsm->rcv_buffer_size = 128 << 10;
-  bsm->prealloc_fifos = 0;
-  bsm->private_segment_count = 0;
-  bsm->private_segment_size = 0;
-  vec_free (bsm->server_uri);
-
-  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
-    {
-      if (unformat (input, "no-echo"))
-	bsm->no_echo = 1;
-      else if (unformat (input, "fifo-size %d", &bsm->fifo_size))
-	bsm->fifo_size <<= 10;
-      else if (unformat (input, "rcv-buf-size %d", &bsm->rcv_buffer_size))
-	;
-      else if (unformat (input, "prealloc-fifos %d", &bsm->prealloc_fifos))
-	;
-      else if (unformat (input, "private-segment-count %d",
-			 &bsm->private_segment_count))
-	;
-      else if (unformat (input, "private-segment-size %U",
-			 unformat_memory_size, &tmp))
-	{
-	  if (tmp >= 0x100000000ULL)
-	    return clib_error_return
-	      (0, "private segment size %lld (%llu) too large", tmp, tmp);
-	  bsm->private_segment_size = tmp;
-	}
-      else if (unformat (input, "uri %s", &bsm->server_uri))
-	server_uri_set = 1;
-      else if (unformat (input, "appns %_%v%_", &appns_id))
-	;
-      else if (unformat (input, "all-scope"))
-	appns_flags |= (APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE
-			| APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE);
-      else if (unformat (input, "local-scope"))
-	appns_flags |= APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
-      else if (unformat (input, "global-scope"))
-	appns_flags |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
-      else if (unformat (input, "secret %lu", &appns_secret))
-	;
-      else
-	return clib_error_return (0, "unknown input `%U'",
-				  format_unformat_error, input);
-    }
-
-  vnet_session_enable_disable (vm, 1 /* turn on SCTP, etc. */ );
-
-  if (!server_uri_set)
-    bsm->server_uri = (char *) format (0, "sctp://0.0.0.0/1234%c", 0);
-
-  rv = server_create (vm, appns_id, appns_flags, appns_secret);
-  vec_free (appns_id);
-  switch (rv)
-    {
-    case 0:
-      break;
-    default:
-      return clib_error_return (0, "server_create returned %d", rv);
-    }
-
-  return 0;
-}
-
-/* *INDENT-OFF* */
-VLIB_CLI_COMMAND (server_create_command, static) =
-{
-  .path = "test sctp server",
-  .short_help = "test sctp server [no echo][fifo-size <mbytes>] "
-      "[rcv-buf-size <bytes>][prealloc-fifos <count>]"
-      "[private-segment-count <count>][private-segment-size <bytes[m|g]>]"
-      "[uri <sctp://ip/port>]",
-  .function = server_create_command_fn,
-};
-/* *INDENT-ON* */
-
-clib_error_t *
-builtin_sctp_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_sctp_server_main_init);
-
-/*
-* fd.io coding-style-patch-verification: ON
-*
-* Local Variables:
-* eval: (c-set-style "gnu")
-* End:
-*/
diff --git a/src/vnet/session-apps/echo_client.c b/src/vnet/session-apps/echo_client.c
new file mode 100644
index 0000000..b8a4fb3
--- /dev/null
+++ b/src/vnet/session-apps/echo_client.c
@@ -0,0 +1,821 @@
+/*
+ * echo_client.c - vpp built-in echo client code
+ *
+ * Copyright (c) 2017 by Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <vnet/vnet.h>
+#include <vlibapi/api.h>
+#include <vlibmemory/api.h>
+#include <vnet/session-apps/echo_client.h>
+
+echo_client_main_t echo_client_main;
+
+#define ECHO_CLIENT_DBG (0)
+
+static void
+signal_evt_to_cli_i (int *code)
+{
+  echo_client_main_t *ecm = &echo_client_main;
+  ASSERT (vlib_get_thread_index () == 0);
+  vlib_process_signal_event (ecm->vlib_main, ecm->cli_node_index, *code, 0);
+}
+
+static void
+signal_evt_to_cli (int code)
+{
+  if (vlib_get_thread_index () != 0)
+    vl_api_rpc_call_main_thread (signal_evt_to_cli_i, (u8 *) & code,
+				 sizeof (code));
+  else
+    signal_evt_to_cli_i (&code);
+}
+
+static void
+send_data_chunk (echo_client_main_t * ecm, session_t * s)
+{
+  u8 *test_data = ecm->connect_test_data;
+  int test_buf_offset;
+  u32 bytes_this_chunk;
+  session_fifo_event_t evt;
+  svm_fifo_t *txf;
+  int rv;
+
+  ASSERT (vec_len (test_data) > 0);
+
+  test_buf_offset = s->bytes_sent % vec_len (test_data);
+  bytes_this_chunk = vec_len (test_data) - test_buf_offset;
+
+  bytes_this_chunk = bytes_this_chunk < s->bytes_to_send
+    ? bytes_this_chunk : s->bytes_to_send;
+
+  txf = s->server_tx_fifo;
+  rv = svm_fifo_enqueue_nowait (txf, bytes_this_chunk,
+				test_data + test_buf_offset);
+
+  /* If we managed to enqueue data... */
+  if (rv > 0)
+    {
+      /* Account for it... */
+      s->bytes_to_send -= rv;
+      s->bytes_sent += rv;
+
+      if (ECHO_CLIENT_DBG)
+	{
+          /* *INDENT-OFF* */
+          ELOG_TYPE_DECLARE (e) =
+            {
+              .format = "tx-enq: xfer %d bytes, sent %u remain %u",
+              .format_args = "i4i4i4",
+            };
+          /* *INDENT-ON* */
+	  struct
+	  {
+	    u32 data[3];
+	  } *ed;
+	  ed = ELOG_DATA (&vlib_global_main.elog_main, e);
+	  ed->data[0] = rv;
+	  ed->data[1] = s->bytes_sent;
+	  ed->data[2] = s->bytes_to_send;
+	}
+
+      /* Poke the session layer */
+      if (svm_fifo_set_event (txf))
+	{
+	  /* Fabricate TX event, send to vpp */
+	  evt.fifo = txf;
+	  evt.event_type = FIFO_EVENT_APP_TX;
+
+	  if (svm_queue_add
+	      (ecm->vpp_event_queue[txf->master_thread_index], (u8 *) & evt,
+	       0 /* do wait for mutex */ ))
+	    clib_warning ("could not enqueue event");
+	}
+    }
+}
+
+static void
+receive_data_chunk (echo_client_main_t * ecm, session_t * s)
+{
+  svm_fifo_t *rx_fifo = s->server_rx_fifo;
+  u32 my_thread_index = vlib_get_thread_index ();
+  int n_read, i;
+
+  if (ecm->test_bytes)
+    {
+      n_read = svm_fifo_dequeue_nowait (rx_fifo,
+					vec_len (ecm->rx_buf
+						 [my_thread_index]),
+					ecm->rx_buf[my_thread_index]);
+    }
+  else
+    {
+      n_read = svm_fifo_max_dequeue (rx_fifo);
+      svm_fifo_dequeue_drop (rx_fifo, n_read);
+    }
+
+  if (n_read > 0)
+    {
+      if (ECHO_CLIENT_DBG)
+	{
+          /* *INDENT-OFF* */
+          ELOG_TYPE_DECLARE (e) =
+            {
+              .format = "rx-deq: %d bytes",
+              .format_args = "i4",
+            };
+          /* *INDENT-ON* */
+	  struct
+	  {
+	    u32 data[1];
+	  } *ed;
+	  ed = ELOG_DATA (&vlib_global_main.elog_main, e);
+	  ed->data[0] = n_read;
+	}
+
+      if (ecm->test_bytes)
+	{
+	  for (i = 0; i < n_read; i++)
+	    {
+	      if (ecm->rx_buf[my_thread_index][i]
+		  != ((s->bytes_received + i) & 0xff))
+		{
+		  clib_warning ("read %d error at byte %lld, 0x%x not 0x%x",
+				n_read, s->bytes_received + i,
+				ecm->rx_buf[my_thread_index][i],
+				((s->bytes_received + i) & 0xff));
+		  ecm->test_failed = 1;
+		}
+	    }
+	}
+      s->bytes_to_receive -= n_read;
+      s->bytes_received += n_read;
+    }
+}
+
+static uword
+echo_client_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
+		     vlib_frame_t * frame)
+{
+  echo_client_main_t *ecm = &echo_client_main;
+  int my_thread_index = vlib_get_thread_index ();
+  session_t *sp;
+  int i;
+  int delete_session;
+  u32 *connection_indices;
+  u32 *connections_this_batch;
+  u32 nconnections_this_batch;
+
+  connection_indices = ecm->connection_index_by_thread[my_thread_index];
+  connections_this_batch =
+    ecm->connections_this_batch_by_thread[my_thread_index];
+
+  if ((ecm->run_test == 0) ||
+      ((vec_len (connection_indices) == 0)
+       && vec_len (connections_this_batch) == 0))
+    return 0;
+
+  /* Grab another pile of connections */
+  if (PREDICT_FALSE (vec_len (connections_this_batch) == 0))
+    {
+      nconnections_this_batch =
+	clib_min (ecm->connections_per_batch, vec_len (connection_indices));
+
+      ASSERT (nconnections_this_batch > 0);
+      vec_validate (connections_this_batch, nconnections_this_batch - 1);
+      clib_memcpy (connections_this_batch,
+		   connection_indices + vec_len (connection_indices)
+		   - nconnections_this_batch,
+		   nconnections_this_batch * sizeof (u32));
+      _vec_len (connection_indices) -= nconnections_this_batch;
+    }
+
+  if (PREDICT_FALSE (ecm->prev_conns != ecm->connections_per_batch
+		     && ecm->prev_conns == vec_len (connections_this_batch)))
+    {
+      ecm->repeats++;
+      ecm->prev_conns = vec_len (connections_this_batch);
+      if (ecm->repeats == 500000)
+	{
+	  clib_warning ("stuck clients");
+	}
+    }
+  else
+    {
+      ecm->prev_conns = vec_len (connections_this_batch);
+      ecm->repeats = 0;
+    }
+
+  for (i = 0; i < vec_len (connections_this_batch); i++)
+    {
+      delete_session = 1;
+
+      sp = pool_elt_at_index (ecm->sessions, connections_this_batch[i]);
+
+      if (sp->bytes_to_send > 0)
+	{
+	  send_data_chunk (ecm, sp);
+	  delete_session = 0;
+	}
+      if (sp->bytes_to_receive > 0)
+	{
+	  receive_data_chunk (ecm, sp);
+	  delete_session = 0;
+	}
+      if (PREDICT_FALSE (delete_session == 1))
+	{
+	  u32 index, thread_index;
+	  stream_session_t *s;
+
+	  __sync_fetch_and_add (&ecm->tx_total, sp->bytes_sent);
+	  __sync_fetch_and_add (&ecm->rx_total, sp->bytes_received);
+
+	  session_parse_handle (sp->vpp_session_handle,
+				&index, &thread_index);
+	  s = session_get_if_valid (index, thread_index);
+
+	  if (s)
+	    {
+	      vnet_disconnect_args_t _a, *a = &_a;
+	      a->handle = session_handle (s);
+	      a->app_index = ecm->app_index;
+	      vnet_disconnect_session (a);
+
+	      vec_delete (connections_this_batch, 1, i);
+	      i--;
+	      __sync_fetch_and_add (&ecm->ready_connections, -1);
+	    }
+	  else
+	    clib_warning ("session AWOL?");
+
+	  /* Kick the debug CLI process */
+	  if (ecm->ready_connections == 0)
+	    {
+	      signal_evt_to_cli (2);
+	    }
+	}
+    }
+
+  ecm->connection_index_by_thread[my_thread_index] = connection_indices;
+  ecm->connections_this_batch_by_thread[my_thread_index] =
+    connections_this_batch;
+  return 0;
+}
+
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (echo_clients_node) =
+{
+  .function = echo_client_node_fn,
+  .name = "echo-clients",
+  .type = VLIB_NODE_TYPE_INPUT,
+  .state = VLIB_NODE_STATE_DISABLED,
+};
+/* *INDENT-ON* */
+
+static int
+create_api_loopback (echo_client_main_t * ecm)
+{
+  api_main_t *am = &api_main;
+  vl_shmem_hdr_t *shmem_hdr;
+
+  shmem_hdr = am->shmem_hdr;
+  ecm->vl_input_queue = shmem_hdr->vl_input_queue;
+  ecm->my_client_index = vl_api_memclnt_create_internal ("echo_client",
+							 ecm->vl_input_queue);
+  return 0;
+}
+
+static int
+echo_clients_init (vlib_main_t * vm)
+{
+  echo_client_main_t *ecm = &echo_client_main;
+  vlib_thread_main_t *vtm = vlib_get_thread_main ();
+  u32 num_threads;
+  int i;
+
+  if (create_api_loopback (ecm))
+    return -1;
+
+  num_threads = 1 /* main thread */  + vtm->n_threads;
+
+  /* Init test data. Bigecmuffer */
+  vec_validate (ecm->connect_test_data, 1024 * 1024 - 1);
+  for (i = 0; i < vec_len (ecm->connect_test_data); i++)
+    ecm->connect_test_data[i] = i & 0xff;
+
+  vec_validate (ecm->rx_buf, num_threads - 1);
+  for (i = 0; i < num_threads; i++)
+    vec_validate (ecm->rx_buf[i], vec_len (ecm->connect_test_data) - 1);
+
+  ecm->is_init = 1;
+
+  vec_validate (ecm->connection_index_by_thread, vtm->n_vlib_mains);
+  vec_validate (ecm->connections_this_batch_by_thread, vtm->n_vlib_mains);
+  vec_validate (ecm->vpp_event_queue, vtm->n_vlib_mains);
+
+  return 0;
+}
+
+static int
+echo_clients_session_connected_callback (u32 app_index, u32 api_context,
+					 stream_session_t * s, u8 is_fail)
+{
+  echo_client_main_t *ecm = &echo_client_main;
+  session_t *session;
+  u32 session_index;
+  u8 thread_index = vlib_get_thread_index ();
+
+  if (is_fail)
+    {
+      clib_warning ("connection %d failed!", api_context);
+      signal_evt_to_cli (-1);
+      return 0;
+    }
+
+  ASSERT (s->thread_index == thread_index);
+
+  if (!ecm->vpp_event_queue[thread_index])
+    ecm->vpp_event_queue[thread_index] =
+      session_manager_get_vpp_event_queue (thread_index);
+
+  /*
+   * Setup session
+   */
+  clib_spinlock_lock_if_init (&ecm->sessions_lock);
+  pool_get (ecm->sessions, session);
+  clib_spinlock_unlock_if_init (&ecm->sessions_lock);
+
+  memset (session, 0, sizeof (*session));
+  session_index = session - ecm->sessions;
+  session->bytes_to_send = ecm->bytes_to_send;
+  session->bytes_to_receive = ecm->no_return ? 0ULL : ecm->bytes_to_send;
+  session->server_rx_fifo = s->server_rx_fifo;
+  session->server_rx_fifo->client_session_index = session_index;
+  session->server_tx_fifo = s->server_tx_fifo;
+  session->server_tx_fifo->client_session_index = session_index;
+  session->vpp_session_handle = session_handle (s);
+
+  vec_add1 (ecm->connection_index_by_thread[thread_index], session_index);
+  __sync_fetch_and_add (&ecm->ready_connections, 1);
+  if (ecm->ready_connections == ecm->expected_connections)
+    {
+      ecm->run_test = 1;
+      /* Signal the CLI process that the action is starting... */
+      signal_evt_to_cli (1);
+    }
+
+  return 0;
+}
+
+static void
+echo_clients_session_reset_callback (stream_session_t * s)
+{
+  if (s->session_state == SESSION_STATE_READY)
+    clib_warning ("Reset active connection %U", format_stream_session, s, 2);
+  stream_session_cleanup (s);
+  return;
+}
+
+static int
+echo_clients_session_create_callback (stream_session_t * s)
+{
+  return 0;
+}
+
+static void
+echo_clients_session_disconnect_callback (stream_session_t * s)
+{
+  echo_client_main_t *ecm = &echo_client_main;
+  vnet_disconnect_args_t _a, *a = &_a;
+  a->handle = session_handle (s);
+  a->app_index = ecm->app_index;
+  vnet_disconnect_session (a);
+  return;
+}
+
+static int
+echo_clients_rx_callback (stream_session_t * s)
+{
+  clib_warning ("BUG");
+  return 0;
+}
+
+/* *INDENT-OFF* */
+static session_cb_vft_t echo_clients = {
+  .session_reset_callback = echo_clients_session_reset_callback,
+  .session_connected_callback = echo_clients_session_connected_callback,
+  .session_accept_callback = echo_clients_session_create_callback,
+  .session_disconnect_callback = echo_clients_session_disconnect_callback,
+  .builtin_server_rx_callback = echo_clients_rx_callback
+};
+/* *INDENT-ON* */
+
+static clib_error_t *
+echo_clients_attach (u8 * appns_id, u64 appns_flags, u64 appns_secret)
+{
+  u32 prealloc_fifos, segment_size = 2 << 20;
+  echo_client_main_t *ecm = &echo_client_main;
+  vnet_app_attach_args_t _a, *a = &_a;
+  u64 options[16];
+  clib_error_t *error = 0;
+
+  memset (a, 0, sizeof (*a));
+  memset (options, 0, sizeof (options));
+
+  a->api_client_index = ecm->my_client_index;
+  a->session_cb_vft = &echo_clients;
+
+  prealloc_fifos = ecm->prealloc_fifos ? ecm->expected_connections : 1;
+
+  if (ecm->private_segment_size)
+    segment_size = ecm->private_segment_size;
+
+  options[APP_OPTIONS_ACCEPT_COOKIE] = 0x12345678;
+  options[APP_OPTIONS_SEGMENT_SIZE] = segment_size;
+  options[APP_OPTIONS_RX_FIFO_SIZE] = ecm->fifo_size;
+  options[APP_OPTIONS_TX_FIFO_SIZE] = ecm->fifo_size;
+  options[APP_OPTIONS_PRIVATE_SEGMENT_COUNT] = ecm->private_segment_count;
+  options[APP_OPTIONS_PREALLOC_FIFO_PAIRS] = prealloc_fifos;
+
+  options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
+  if (appns_id)
+    {
+      options[APP_OPTIONS_FLAGS] |= appns_flags;
+      options[APP_OPTIONS_NAMESPACE_SECRET] = appns_secret;
+    }
+  a->options = options;
+  a->namespace_id = appns_id;
+
+  if ((error = vnet_application_attach (a)))
+    return error;
+
+  ecm->app_index = a->app_index;
+  return 0;
+}
+
+static int
+echo_clients_detach ()
+{
+  echo_client_main_t *ecm = &echo_client_main;
+  vnet_app_detach_args_t _da, *da = &_da;
+  int rv;
+
+  da->app_index = ecm->app_index;
+  rv = vnet_application_detach (da);
+  ecm->test_client_attached = 0;
+  ecm->app_index = ~0;
+  return rv;
+}
+
+static void *
+echo_client_thread_fn (void *arg)
+{
+  return 0;
+}
+
+/** Start a transmit thread */
+int
+echo_clients_start_tx_pthread (echo_client_main_t * ecm)
+{
+  if (ecm->client_thread_handle == 0)
+    {
+      int rv = pthread_create (&ecm->client_thread_handle,
+			       NULL /*attr */ ,
+			       echo_client_thread_fn, 0);
+      if (rv)
+	{
+	  ecm->client_thread_handle = 0;
+	  return -1;
+	}
+    }
+  return 0;
+}
+
+clib_error_t *
+echo_clients_connect (vlib_main_t * vm, u32 n_clients)
+{
+  echo_client_main_t *ecm = &echo_client_main;
+  vnet_connect_args_t _a, *a = &_a;
+  clib_error_t *error = 0;
+  int i;
+  for (i = 0; i < n_clients; i++)
+    {
+      memset (a, 0, sizeof (*a));
+
+      a->uri = (char *) ecm->connect_uri;
+      a->api_context = i;
+      a->app_index = ecm->app_index;
+      a->mp = 0;
+
+      if ((error = vnet_connect_uri (a)))
+	return error;
+
+      /* Crude pacing for call setups  */
+      if ((i % 4) == 0)
+	vlib_process_suspend (vm, 10e-6);
+      ASSERT (i + 1 >= ecm->ready_connections);
+      while (i + 1 - ecm->ready_connections > 1000)
+	{
+	  vlib_process_suspend (vm, 100e-6);
+	}
+    }
+  return 0;
+}
+
+#define ec_cli_output(_fmt, _args...) 			\
+  if (!ecm->no_output)  					\
+    vlib_cli_output(vm, _fmt, ##_args)
+
+static clib_error_t *
+echo_clients_command_fn (vlib_main_t * vm,
+			 unformat_input_t * input, vlib_cli_command_t * cmd)
+{
+  echo_client_main_t *ecm = &echo_client_main;
+  vlib_thread_main_t *thread_main = vlib_get_thread_main ();
+  uword *event_data = 0, event_type;
+  u8 *default_uri = (u8 *) "tcp://6.0.1.1/1234", *appns_id = 0;
+  u64 tmp, total_bytes, appns_flags = 0, appns_secret = 0;
+  f64 test_timeout = 20.0, syn_timeout = 20.0, delta;
+  f64 time_before_connects;
+  u32 n_clients = 1;
+  int preallocate_sessions = 0;
+  char *transfer_type;
+  clib_error_t *error = 0;
+  int i;
+
+  ecm->bytes_to_send = 8192;
+  ecm->no_return = 0;
+  ecm->fifo_size = 64 << 10;
+  ecm->connections_per_batch = 1000;
+  ecm->private_segment_count = 0;
+  ecm->private_segment_size = 0;
+  ecm->no_output = 0;
+  ecm->test_bytes = 0;
+  ecm->test_failed = 0;
+  ecm->vlib_main = vm;
+  if (thread_main->n_vlib_mains > 1)
+    clib_spinlock_init (&ecm->sessions_lock);
+  vec_free (ecm->connect_uri);
+
+  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (input, "uri %s", &ecm->connect_uri))
+	;
+      else if (unformat (input, "nclients %d", &n_clients))
+	;
+      else if (unformat (input, "mbytes %lld", &tmp))
+	ecm->bytes_to_send = tmp << 20;
+      else if (unformat (input, "gbytes %lld", &tmp))
+	ecm->bytes_to_send = tmp << 30;
+      else if (unformat (input, "bytes %lld", &ecm->bytes_to_send))
+	;
+      else if (unformat (input, "test-timeout %f", &test_timeout))
+	;
+      else if (unformat (input, "syn-timeout %f", &syn_timeout))
+	;
+      else if (unformat (input, "no-return"))
+	ecm->no_return = 1;
+      else if (unformat (input, "fifo-size %d", &ecm->fifo_size))
+	ecm->fifo_size <<= 10;
+      else if (unformat (input, "private-segment-count %d",
+			 &ecm->private_segment_count))
+	;
+      else if (unformat (input, "private-segment-size %U",
+			 unformat_memory_size, &tmp))
+	{
+	  if (tmp >= 0x100000000ULL)
+	    return clib_error_return
+	      (0, "private segment size %lld (%llu) too large", tmp, tmp);
+	  ecm->private_segment_size = tmp;
+	}
+      else if (unformat (input, "preallocate-fifos"))
+	ecm->prealloc_fifos = 1;
+      else if (unformat (input, "preallocate-sessions"))
+	preallocate_sessions = 1;
+      else
+	if (unformat (input, "client-batch %d", &ecm->connections_per_batch))
+	;
+      else if (unformat (input, "appns %_%v%_", &appns_id))
+	;
+      else if (unformat (input, "all-scope"))
+	appns_flags |= (APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE
+			| APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE);
+      else if (unformat (input, "local-scope"))
+	appns_flags = APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
+      else if (unformat (input, "global-scope"))
+	appns_flags = APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
+      else if (unformat (input, "secret %lu", &appns_secret))
+	;
+      else if (unformat (input, "no-output"))
+	ecm->no_output = 1;
+      else if (unformat (input, "test-bytes"))
+	ecm->test_bytes = 1;
+      else
+	return clib_error_return (0, "unknown input `%U'",
+				  format_unformat_error, input);
+    }
+
+  /* Store cli process node index for signalling */
+  ecm->cli_node_index =
+    vlib_get_current_process (vm)->node_runtime.node_index;
+
+  if (ecm->is_init == 0)
+    {
+      if (echo_clients_init (vm))
+	return clib_error_return (0, "failed init");
+    }
+
+
+  ecm->ready_connections = 0;
+  ecm->expected_connections = n_clients;
+  ecm->rx_total = 0;
+  ecm->tx_total = 0;
+
+  if (!ecm->connect_uri)
+    {
+      clib_warning ("No uri provided. Using default: %v", default_uri);
+      ecm->connect_uri = default_uri;
+    }
+
+#if ECHO_CLIENT_PTHREAD
+  echo_clients_start_tx_pthread ();
+#endif
+
+  vlib_worker_thread_barrier_sync (vm);
+  vnet_session_enable_disable (vm, 1 /* turn on session and transports */ );
+  vlib_worker_thread_barrier_release (vm);
+
+  if (ecm->test_client_attached == 0)
+    {
+      if ((error = echo_clients_attach (appns_id, appns_flags, appns_secret)))
+	{
+	  vec_free (appns_id);
+	  clib_error_report (error);
+	  return error;
+	}
+      vec_free (appns_id);
+    }
+  ecm->test_client_attached = 1;
+
+  /* Turn on the builtin client input nodes */
+  for (i = 0; i < thread_main->n_vlib_mains; i++)
+    vlib_node_set_state (vlib_mains[i], echo_clients_node.index,
+			 VLIB_NODE_STATE_POLLING);
+
+  if (preallocate_sessions)
+    {
+      session_t *sp __attribute__ ((unused));
+      for (i = 0; i < n_clients; i++)
+	pool_get (ecm->sessions, sp);
+      for (i = 0; i < n_clients; i++)
+	pool_put_index (ecm->sessions, i);
+    }
+
+  /* Fire off connect requests */
+  time_before_connects = vlib_time_now (vm);
+  if ((error = echo_clients_connect (vm, n_clients)))
+    return error;
+
+  /* Park until the sessions come up, or ten seconds elapse... */
+  vlib_process_wait_for_event_or_clock (vm, syn_timeout);
+  event_type = vlib_process_get_events (vm, &event_data);
+  switch (event_type)
+    {
+    case ~0:
+      ec_cli_output ("Timeout with only %d sessions active...",
+		     ecm->ready_connections);
+      error = clib_error_return (0, "failed: syn timeout with %d sessions",
+				 ecm->ready_connections);
+      goto cleanup;
+
+    case 1:
+      delta = vlib_time_now (vm) - time_before_connects;
+      if (delta != 0.0)
+	ec_cli_output ("%d three-way handshakes in %.2f seconds %.2f/s",
+		       n_clients, delta, ((f64) n_clients) / delta);
+
+      ecm->test_start_time = vlib_time_now (ecm->vlib_main);
+      ec_cli_output ("Test started at %.6f", ecm->test_start_time);
+      break;
+
+    default:
+      ec_cli_output ("unexpected event(1): %d", event_type);
+      error = clib_error_return (0, "failed: unexpected event(1): %d",
+				 event_type);
+      goto cleanup;
+    }
+
+  /* Now wait for the sessions to finish... */
+  vlib_process_wait_for_event_or_clock (vm, test_timeout);
+  event_type = vlib_process_get_events (vm, &event_data);
+  switch (event_type)
+    {
+    case ~0:
+      ec_cli_output ("Timeout with %d sessions still active...",
+		     ecm->ready_connections);
+      error = clib_error_return (0, "failed: timeout with %d sessions",
+				 ecm->ready_connections);
+      goto cleanup;
+
+    case 2:
+      ecm->test_end_time = vlib_time_now (vm);
+      ec_cli_output ("Test finished at %.6f", ecm->test_end_time);
+      break;
+
+    default:
+      ec_cli_output ("unexpected event(2): %d", event_type);
+      error = clib_error_return (0, "failed: unexpected event(2): %d",
+				 event_type);
+      goto cleanup;
+    }
+
+  delta = ecm->test_end_time - ecm->test_start_time;
+  if (delta != 0.0)
+    {
+      total_bytes = (ecm->no_return ? ecm->tx_total : ecm->rx_total);
+      transfer_type = ecm->no_return ? "half-duplex" : "full-duplex";
+      ec_cli_output ("%lld bytes (%lld mbytes, %lld gbytes) in %.2f seconds",
+		     total_bytes, total_bytes / (1ULL << 20),
+		     total_bytes / (1ULL << 30), delta);
+      ec_cli_output ("%.2f bytes/second %s", ((f64) total_bytes) / (delta),
+		     transfer_type);
+      ec_cli_output ("%.4f gbit/second %s",
+		     (((f64) total_bytes * 8.0) / delta / 1e9),
+		     transfer_type);
+    }
+  else
+    {
+      ec_cli_output ("zero delta-t?");
+      error = clib_error_return (0, "failed: zero delta-t");
+      goto cleanup;
+    }
+
+  if (ecm->test_bytes && ecm->test_failed)
+    error = clib_error_return (0, "failed: test bytes");
+
+cleanup:
+  ecm->run_test = 0;
+  for (i = 0; i < vec_len (ecm->connection_index_by_thread); i++)
+    {
+      vec_reset_length (ecm->connection_index_by_thread[i]);
+      vec_reset_length (ecm->connections_this_batch_by_thread[i]);
+    }
+
+  pool_free (ecm->sessions);
+
+  /* Detach the application, so we can use different fifo sizes next time */
+  if (ecm->test_client_attached)
+    {
+      if (echo_clients_detach ())
+	{
+	  error = clib_error_return (0, "failed: app detach");
+	  ec_cli_output ("WARNING: app detach failed...");
+	}
+    }
+  if (error)
+    ec_cli_output ("test failed");
+  return error;
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (echo_clients_command, static) =
+{
+  .path = "test echo clients",
+  .short_help = "test echo clients [nclients %d][[m|g]bytes <bytes>]"
+      "[test-timeout <time>][syn-timeout <time>][no-return][fifo-size <size>]"
+      "[private-segment-count <count>][private-segment-size <bytes>[m|g]]"
+      "[preallocate-fifos][preallocate-sessions][client-batch <batch-size>]"
+      "[uri <tcp://ip/port>][test-bytes][no-output]",
+  .function = echo_clients_command_fn,
+  .is_mp_safe = 1,
+};
+/* *INDENT-ON* */
+
+clib_error_t *
+echo_clients_main_init (vlib_main_t * vm)
+{
+  echo_client_main_t *ecm = &echo_client_main;
+  ecm->is_init = 0;
+  return 0;
+}
+
+VLIB_INIT_FUNCTION (echo_clients_main_init);
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/vnet/tcp/builtin_client.h b/src/vnet/session-apps/echo_client.h
similarity index 89%
rename from src/vnet/tcp/builtin_client.h
rename to src/vnet/session-apps/echo_client.h
index be8ea00..4ae63ec 100644
--- a/src/vnet/tcp/builtin_client.h
+++ b/src/vnet/session-apps/echo_client.h
@@ -1,6 +1,6 @@
 
 /*
- * tclient.h - skeleton vpp engine plug-in header file
+ * echo_client.h - built-in application layer echo client
  *
  * Copyright (c) <current-year> <your-organization>
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,8 +15,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#ifndef __included_tclient_h__
-#define __included_tclient_h__
+#ifndef __included_echo_client_h__
+#define __included_echo_client_h__
 
 #include <vnet/vnet.h>
 #include <vnet/ip/ip.h>
@@ -100,19 +100,14 @@
   u8 test_bytes;
   u8 test_failed;
 
-  /*
-   * Convenience
-   */
   vlib_main_t *vlib_main;
-  vnet_main_t *vnet_main;
-  ethernet_main_t *ethernet_main;
-} tclient_main_t;
+} echo_client_main_t;
 
-extern tclient_main_t tclient_main;
+extern echo_client_main_t echo_client_main;
 
-vlib_node_registration_t tclient_node;
+vlib_node_registration_t echo_clients_node;
 
-#endif /* __included_tclient_h__ */
+#endif /* __included_echo_client_h__ */
 
 /*
  * fd.io coding-style-patch-verification: ON
diff --git a/src/vnet/session-apps/echo_server.c b/src/vnet/session-apps/echo_server.c
new file mode 100644
index 0000000..37a51d5
--- /dev/null
+++ b/src/vnet/session-apps/echo_server.c
@@ -0,0 +1,485 @@
+/*
+* Copyright (c) 2015-2017 Cisco and/or its affiliates.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at:
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#include <vnet/vnet.h>
+#include <vlibmemory/api.h>
+#include <vnet/session/application.h>
+#include <vnet/session/application_interface.h>
+
+typedef struct
+{
+  /*
+   * Server app parameters
+   */
+  svm_queue_t **vpp_queue;
+  svm_queue_t *vl_input_queue;	/**< Sever's event queue */
+
+  u32 app_index;		/**< Server app index */
+  u32 my_client_index;		/**< API client handle */
+  u32 node_index;		/**< process node index for evnt scheduling */
+
+  /*
+   * Config params
+   */
+  u8 no_echo;			/**< Don't echo traffic */
+  u32 fifo_size;			/**< Fifo size */
+  u32 rcv_buffer_size;		/**< Rcv buffer size */
+  u32 prealloc_fifos;		/**< Preallocate fifos */
+  u32 private_segment_count;	/**< Number of private segments  */
+  u32 private_segment_size;	/**< Size of private segments  */
+  char *server_uri;		/**< Server URI */
+
+  /*
+   * Test state
+   */
+  u8 **rx_buf;			/**< Per-thread RX buffer */
+  u64 byte_index;
+  u32 **rx_retries;
+
+  vlib_main_t *vlib_main;
+} echo_server_main_t;
+
+echo_server_main_t echo_server_main;
+
+int
+echo_server_session_accept_callback (stream_session_t * s)
+{
+  echo_server_main_t *esm = &echo_server_main;
+
+  esm->vpp_queue[s->thread_index] =
+    session_manager_get_vpp_event_queue (s->thread_index);
+  s->session_state = SESSION_STATE_READY;
+  esm->byte_index = 0;
+  vec_validate (esm->rx_retries[s->thread_index], s->session_index);
+  esm->rx_retries[s->thread_index][s->session_index] = 0;
+  return 0;
+}
+
+void
+echo_server_session_disconnect_callback (stream_session_t * s)
+{
+  echo_server_main_t *esm = &echo_server_main;
+  vnet_disconnect_args_t _a, *a = &_a;
+
+  a->handle = session_handle (s);
+  a->app_index = esm->app_index;
+  vnet_disconnect_session (a);
+}
+
+void
+echo_server_session_reset_callback (stream_session_t * s)
+{
+  clib_warning ("Reset session %U", format_stream_session, s, 2);
+  stream_session_cleanup (s);
+}
+
+int
+echo_server_session_connected_callback (u32 app_index, u32 api_context,
+					stream_session_t * s, u8 is_fail)
+{
+  clib_warning ("called...");
+  return -1;
+}
+
+int
+echo_server_add_segment_callback (u32 client_index, const ssvm_private_t * sp)
+{
+  clib_warning ("called...");
+  return -1;
+}
+
+int
+echo_server_redirect_connect_callback (u32 client_index, void *mp)
+{
+  clib_warning ("called...");
+  return -1;
+}
+
+void
+test_bytes (echo_server_main_t * esm, int actual_transfer)
+{
+  int i;
+  u32 my_thread_id = vlib_get_thread_index ();
+
+  for (i = 0; i < actual_transfer; i++)
+    {
+      if (esm->rx_buf[my_thread_id][i] != ((esm->byte_index + i) & 0xff))
+	{
+	  clib_warning ("at %lld expected %d got %d", esm->byte_index + i,
+			(esm->byte_index + i) & 0xff,
+			esm->rx_buf[my_thread_id][i]);
+	}
+    }
+  esm->byte_index += actual_transfer;
+}
+
+/*
+ * If no-echo, just read the data and be done with it
+ */
+int
+echo_server_builtin_server_rx_callback_no_echo (stream_session_t * s)
+{
+  echo_server_main_t *esm = &echo_server_main;
+  u32 my_thread_id = vlib_get_thread_index ();
+  int actual_transfer;
+  svm_fifo_t *rx_fifo;
+
+  rx_fifo = s->server_rx_fifo;
+
+  do
+    {
+      actual_transfer =
+	svm_fifo_dequeue_nowait (rx_fifo, esm->rcv_buffer_size,
+				 esm->rx_buf[my_thread_id]);
+    }
+  while (actual_transfer > 0);
+  return 0;
+}
+
+int
+echo_server_rx_callback (stream_session_t * s)
+{
+  u32 n_written, max_dequeue, max_enqueue, max_transfer;
+  int actual_transfer;
+  svm_fifo_t *tx_fifo, *rx_fifo;
+  echo_server_main_t *esm = &echo_server_main;
+  session_fifo_event_t evt;
+  u32 thread_index = vlib_get_thread_index ();
+
+  ASSERT (s->thread_index == thread_index);
+
+  rx_fifo = s->server_rx_fifo;
+  tx_fifo = s->server_tx_fifo;
+
+  ASSERT (rx_fifo->master_thread_index == thread_index);
+  ASSERT (tx_fifo->master_thread_index == thread_index);
+
+  max_dequeue = svm_fifo_max_dequeue (s->server_rx_fifo);
+  max_enqueue = svm_fifo_max_enqueue (s->server_tx_fifo);
+
+  if (PREDICT_FALSE (max_dequeue == 0))
+    return 0;
+
+  /* Number of bytes we're going to copy */
+  max_transfer = (max_dequeue < max_enqueue) ? max_dequeue : max_enqueue;
+
+  /* No space in tx fifo */
+  if (PREDICT_FALSE (max_transfer == 0))
+    {
+      /* XXX timeout for session that are stuck */
+
+    rx_event:
+      /* Program self-tap to retry */
+      if (svm_fifo_set_event (rx_fifo))
+	{
+	  svm_queue_t *q;
+	  evt.fifo = rx_fifo;
+	  evt.event_type = FIFO_EVENT_BUILTIN_RX;
+
+	  q = esm->vpp_queue[thread_index];
+	  if (PREDICT_FALSE (q->cursize == q->maxsize))
+	    clib_warning ("out of event queue space");
+	  else if (svm_queue_add (q, (u8 *) & evt, 0))
+	    clib_warning ("failed to enqueue self-tap");
+
+	  if (esm->rx_retries[thread_index][s->session_index] == 500000)
+	    {
+	      clib_warning ("session stuck: %U", format_stream_session, s, 2);
+	    }
+	  if (esm->rx_retries[thread_index][s->session_index] < 500001)
+	    esm->rx_retries[thread_index][s->session_index]++;
+	}
+
+      return 0;
+    }
+
+  _vec_len (esm->rx_buf[thread_index]) = max_transfer;
+
+  actual_transfer = svm_fifo_dequeue_nowait (rx_fifo, max_transfer,
+					     esm->rx_buf[thread_index]);
+  ASSERT (actual_transfer == max_transfer);
+
+//  test_bytes (esm, actual_transfer);
+
+  /*
+   * Echo back
+   */
+
+  n_written = svm_fifo_enqueue_nowait (tx_fifo, actual_transfer,
+				       esm->rx_buf[thread_index]);
+
+  if (n_written != max_transfer)
+    clib_warning ("short trout!");
+
+  if (svm_fifo_set_event (tx_fifo))
+    {
+      /* Fabricate TX event, send to vpp */
+      evt.fifo = tx_fifo;
+      evt.event_type = FIFO_EVENT_APP_TX;
+
+      if (svm_queue_add (esm->vpp_queue[s->thread_index],
+			 (u8 *) & evt, 0 /* do wait for mutex */ ))
+	clib_warning ("failed to enqueue tx evt");
+    }
+
+  if (PREDICT_FALSE (n_written < max_dequeue))
+    goto rx_event;
+
+  return 0;
+}
+
+static session_cb_vft_t echo_server_session_cb_vft = {
+  .session_accept_callback = echo_server_session_accept_callback,
+  .session_disconnect_callback = echo_server_session_disconnect_callback,
+  .session_connected_callback = echo_server_session_connected_callback,
+  .add_segment_callback = echo_server_add_segment_callback,
+  .redirect_connect_callback = echo_server_redirect_connect_callback,
+  .builtin_server_rx_callback = echo_server_rx_callback,
+  .session_reset_callback = echo_server_session_reset_callback
+};
+
+/* Abuse VPP's input queue */
+static int
+create_api_loopback (vlib_main_t * vm)
+{
+  echo_server_main_t *esm = &echo_server_main;
+  api_main_t *am = &api_main;
+  vl_shmem_hdr_t *shmem_hdr;
+
+  shmem_hdr = am->shmem_hdr;
+  esm->vl_input_queue = shmem_hdr->vl_input_queue;
+  esm->my_client_index = vl_api_memclnt_create_internal ("echo_server",
+							 esm->vl_input_queue);
+  return 0;
+}
+
+static int
+echo_server_attach (u8 * appns_id, u64 appns_flags, u64 appns_secret)
+{
+  echo_server_main_t *esm = &echo_server_main;
+  u64 options[APP_OPTIONS_N_OPTIONS];
+  vnet_app_attach_args_t _a, *a = &_a;
+  u32 segment_size = 512 << 20;
+
+  memset (a, 0, sizeof (*a));
+  memset (options, 0, sizeof (options));
+
+  if (esm->no_echo)
+    echo_server_session_cb_vft.builtin_server_rx_callback =
+      echo_server_builtin_server_rx_callback_no_echo;
+  else
+    echo_server_session_cb_vft.builtin_server_rx_callback =
+      echo_server_rx_callback;
+
+  if (esm->private_segment_size)
+    segment_size = esm->private_segment_size;
+
+  a->api_client_index = esm->my_client_index;
+  a->session_cb_vft = &echo_server_session_cb_vft;
+  a->options = options;
+  a->options[APP_OPTIONS_SEGMENT_SIZE] = segment_size;
+  a->options[APP_OPTIONS_RX_FIFO_SIZE] = esm->fifo_size;
+  a->options[APP_OPTIONS_TX_FIFO_SIZE] = esm->fifo_size;
+  a->options[APP_OPTIONS_PRIVATE_SEGMENT_COUNT] = esm->private_segment_count;
+  a->options[APP_OPTIONS_PREALLOC_FIFO_PAIRS] =
+    esm->prealloc_fifos ? esm->prealloc_fifos : 1;
+
+  a->options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
+  if (appns_id)
+    {
+      a->namespace_id = appns_id;
+      a->options[APP_OPTIONS_FLAGS] |= appns_flags;
+      a->options[APP_OPTIONS_NAMESPACE_SECRET] = appns_secret;
+    }
+
+  if (vnet_application_attach (a))
+    {
+      clib_warning ("failed to attach server");
+      return -1;
+    }
+  esm->app_index = a->app_index;
+  return 0;
+}
+
+static int
+echo_server_detach (void)
+{
+  echo_server_main_t *esm = &echo_server_main;
+  vnet_app_detach_args_t _da, *da = &_da;
+  int rv;
+
+  da->app_index = esm->app_index;
+  rv = vnet_application_detach (da);
+  esm->app_index = ~0;
+  return rv;
+}
+
+static int
+echo_server_listen ()
+{
+  echo_server_main_t *esm = &echo_server_main;
+  vnet_bind_args_t _a, *a = &_a;
+  memset (a, 0, sizeof (*a));
+  a->app_index = esm->app_index;
+  a->uri = esm->server_uri;
+  return vnet_bind_uri (a);
+}
+
+static int
+echo_server_create (vlib_main_t * vm, u8 * appns_id, u64 appns_flags,
+		    u64 appns_secret)
+{
+  echo_server_main_t *esm = &echo_server_main;
+  vlib_thread_main_t *vtm = vlib_get_thread_main ();
+  u32 num_threads;
+  int i;
+
+  if (esm->my_client_index == (u32) ~ 0)
+    {
+      if (create_api_loopback (vm))
+	{
+	  clib_warning ("failed to create api loopback");
+	  return -1;
+	}
+    }
+
+  num_threads = 1 /* main thread */  + vtm->n_threads;
+  vec_validate (echo_server_main.vpp_queue, num_threads - 1);
+  vec_validate (esm->rx_buf, num_threads - 1);
+  vec_validate (esm->rx_retries, num_threads - 1);
+
+  for (i = 0; i < num_threads; i++)
+    vec_validate (esm->rx_buf[i], esm->rcv_buffer_size);
+
+  if (echo_server_attach (appns_id, appns_flags, appns_secret))
+    {
+      clib_warning ("failed to attach server");
+      return -1;
+    }
+  if (echo_server_listen ())
+    {
+      clib_warning ("failed to start listening");
+      if (echo_server_detach ())
+	clib_warning ("failed to detach");
+      return -1;
+    }
+  return 0;
+}
+
+static clib_error_t *
+echo_server_create_command_fn (vlib_main_t * vm, unformat_input_t * input,
+			       vlib_cli_command_t * cmd)
+{
+  echo_server_main_t *esm = &echo_server_main;
+  u8 server_uri_set = 0, *appns_id = 0;
+  u64 tmp, appns_flags = 0, appns_secret = 0;
+  char *default_uri = "tcp://0.0.0.0/1234";
+  int rv;
+
+  esm->no_echo = 0;
+  esm->fifo_size = 64 << 10;
+  esm->rcv_buffer_size = 128 << 10;
+  esm->prealloc_fifos = 0;
+  esm->private_segment_count = 0;
+  esm->private_segment_size = 0;
+  vec_free (esm->server_uri);
+
+  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (input, "uri %s", &esm->server_uri))
+	server_uri_set = 1;
+      else if (unformat (input, "no-echo"))
+	esm->no_echo = 1;
+      else if (unformat (input, "fifo-size %d", &esm->fifo_size))
+	esm->fifo_size <<= 10;
+      else if (unformat (input, "rcv-buf-size %d", &esm->rcv_buffer_size))
+	;
+      else if (unformat (input, "prealloc-fifos %d", &esm->prealloc_fifos))
+	;
+      else if (unformat (input, "private-segment-count %d",
+			 &esm->private_segment_count))
+	;
+      else if (unformat (input, "private-segment-size %U",
+			 unformat_memory_size, &tmp))
+	{
+	  if (tmp >= 0x100000000ULL)
+	    return clib_error_return
+	      (0, "private segment size %lld (%llu) too large", tmp, tmp);
+	  esm->private_segment_size = tmp;
+	}
+      else if (unformat (input, "appns %_%v%_", &appns_id))
+	;
+      else if (unformat (input, "all-scope"))
+	appns_flags |= (APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE
+			| APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE);
+      else if (unformat (input, "local-scope"))
+	appns_flags |= APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
+      else if (unformat (input, "global-scope"))
+	appns_flags |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
+      else if (unformat (input, "secret %lu", &appns_secret))
+	;
+      else
+	return clib_error_return (0, "failed: unknown input `%U'",
+				  format_unformat_error, input);
+    }
+
+  vnet_session_enable_disable (vm, 1 /* turn on TCP, etc. */ );
+
+  if (!server_uri_set)
+    {
+      clib_warning ("No uri provided! Using default: %s", default_uri);
+      esm->server_uri = (char *) format (0, "%s%c", default_uri, 0);
+    }
+
+  rv = echo_server_create (vm, appns_id, appns_flags, appns_secret);
+  vec_free (appns_id);
+  if (rv)
+    {
+      vec_free (esm->server_uri);
+      return clib_error_return (0, "failed: server_create returned %d", rv);
+    }
+
+  return 0;
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (echo_server_create_command, static) =
+{
+  .path = "test echo server",
+  .short_help = "test echo server proto <proto> [no echo][fifo-size <mbytes>]"
+      "[rcv-buf-size <bytes>][prealloc-fifos <count>]"
+      "[private-segment-count <count>][private-segment-size <bytes[m|g]>]"
+      "[uri <tcp://ip/port>]",
+  .function = echo_server_create_command_fn,
+};
+/* *INDENT-ON* */
+
+clib_error_t *
+echo_server_main_init (vlib_main_t * vm)
+{
+  echo_server_main_t *esm = &echo_server_main;
+  esm->my_client_index = ~0;
+  return 0;
+}
+
+VLIB_INIT_FUNCTION (echo_server_main_init);
+
+/*
+* fd.io coding-style-patch-verification: ON
+*
+* Local Variables:
+* eval: (c-set-style "gnu")
+* End:
+*/
diff --git a/src/vnet/tcp/builtin_http_server.c b/src/vnet/session-apps/http_server.c
similarity index 88%
rename from src/vnet/tcp/builtin_http_server.c
rename to src/vnet/session-apps/http_server.c
index 5510f8a..07eaab4 100644
--- a/src/vnet/tcp/builtin_http_server.c
+++ b/src/vnet/session-apps/http_server.c
@@ -27,7 +27,7 @@
   u64 session_handle;
   u64 node_index;
   u8 *data;
-} builtin_http_server_args;
+} http_server_args;
 
 typedef struct
 {
@@ -59,14 +59,14 @@
 http_server_main_t http_server_main;
 
 static void
-free_http_process (builtin_http_server_args * args)
+free_http_process (http_server_args * args)
 {
   vlib_node_runtime_t *rt;
   vlib_main_t *vm = &vlib_global_main;
   http_server_main_t *hsm = &http_server_main;
   vlib_node_t *n;
   u32 node_index;
-  builtin_http_server_args **save_args;
+  http_server_args **save_args;
 
   node_index = args->node_index;
   ASSERT (node_index != 0);
@@ -199,8 +199,8 @@
 {
   http_server_main_t *hsm = &http_server_main;
   u8 *request = 0, *reply = 0;
-  builtin_http_server_args **save_args;
-  builtin_http_server_args *args;
+  http_server_args **save_args;
+  http_server_args *args;
   stream_session_t *s;
   unformat_input_t input;
   int i;
@@ -281,14 +281,14 @@
 }
 
 static void
-alloc_http_process (builtin_http_server_args * args)
+alloc_http_process (http_server_args * args)
 {
   char *name;
   vlib_node_t *n;
   http_server_main_t *hsm = &http_server_main;
   vlib_main_t *vm = hsm->vlib_main;
   uword l = vec_len (hsm->free_http_cli_process_node_indices);
-  builtin_http_server_args **save_args;
+  http_server_args **save_args;
 
   if (vec_len (hsm->free_http_cli_process_node_indices) > 0)
     {
@@ -326,7 +326,7 @@
 static void
 alloc_http_process_callback (void *cb_args)
 {
-  alloc_http_process ((builtin_http_server_args *) cb_args);
+  alloc_http_process ((http_server_args *) cb_args);
 }
 
 static int
@@ -357,7 +357,7 @@
 http_server_rx_callback (stream_session_t * s)
 {
   http_server_main_t *hsm = &http_server_main;
-  builtin_http_server_args *args;
+  http_server_args *args;
   int rv;
 
   rv = session_rx_request (s);
@@ -427,7 +427,7 @@
 }
 
 static int
-builtin_session_accept_callback (stream_session_t * s)
+http_server_session_accept_callback (stream_session_t * s)
 {
   http_server_main_t *bsm = &http_server_main;
 
@@ -439,7 +439,7 @@
 }
 
 static void
-builtin_session_disconnect_callback (stream_session_t * s)
+http_server_session_disconnect_callback (stream_session_t * s)
 {
   http_server_main_t *bsm = &http_server_main;
   vnet_disconnect_args_t _a, *a = &_a;
@@ -450,43 +450,42 @@
 }
 
 static void
-builtin_session_reset_callback (stream_session_t * s)
+http_server_session_reset_callback (stream_session_t * s)
 {
   clib_warning ("called.. ");
-
   stream_session_cleanup (s);
 }
 
 static int
-builtin_session_connected_callback (u32 app_index, u32 api_context,
-				    stream_session_t * s, u8 is_fail)
+http_server_session_connected_callback (u32 app_index, u32 api_context,
+					stream_session_t * s, u8 is_fail)
 {
   clib_warning ("called...");
   return -1;
 }
 
 static int
-builtin_add_segment_callback (u32 client_index, const ssvm_private_t * sp)
+http_server_add_segment_callback (u32 client_index, const ssvm_private_t * sp)
 {
   clib_warning ("called...");
   return -1;
 }
 
 static int
-builtin_redirect_connect_callback (u32 client_index, void *mp)
+http_server_redirect_connect_callback (u32 client_index, void *mp)
 {
   clib_warning ("called...");
   return -1;
 }
 
-static session_cb_vft_t builtin_session_cb_vft = {
-  .session_accept_callback = builtin_session_accept_callback,
-  .session_disconnect_callback = builtin_session_disconnect_callback,
-  .session_connected_callback = builtin_session_connected_callback,
-  .add_segment_callback = builtin_add_segment_callback,
-  .redirect_connect_callback = builtin_redirect_connect_callback,
+static session_cb_vft_t http_server_session_cb_vft = {
+  .session_accept_callback = http_server_session_accept_callback,
+  .session_disconnect_callback = http_server_session_disconnect_callback,
+  .session_connected_callback = http_server_session_connected_callback,
+  .add_segment_callback = http_server_add_segment_callback,
+  .redirect_connect_callback = http_server_redirect_connect_callback,
   .builtin_server_rx_callback = http_server_rx_callback,
-  .session_reset_callback = builtin_session_reset_callback
+  .session_reset_callback = http_server_session_reset_callback
 };
 
 /* Abuse VPP's input queue */
@@ -500,7 +499,7 @@
   shmem_hdr = am->shmem_hdr;
   hsm->vl_input_queue = shmem_hdr->vl_input_queue;
   hsm->my_client_index =
-    vl_api_memclnt_create_internal ("test_http_server", hsm->vl_input_queue);
+    vl_api_memclnt_create_internal ("http_server", hsm->vl_input_queue);
   return 0;
 }
 
@@ -519,7 +518,7 @@
     segment_size = hsm->private_segment_size;
 
   a->api_client_index = hsm->my_client_index;
-  a->session_cb_vft = &builtin_session_cb_vft;
+  a->session_cb_vft = &http_server_session_cb_vft;
   a->options = options;
   a->options[APP_OPTIONS_SEGMENT_SIZE] = segment_size;
   a->options[APP_OPTIONS_RX_FIFO_SIZE] =
@@ -539,7 +538,7 @@
 }
 
 static int
-server_listen ()
+http_server_listen ()
 {
   http_server_main_t *hsm = &http_server_main;
   vnet_bind_args_t _a, *a = &_a;
@@ -550,7 +549,7 @@
 }
 
 static int
-server_create (vlib_main_t * vm)
+http_server_create (vlib_main_t * vm)
 {
   http_server_main_t *hsm = &http_server_main;
   u32 num_threads;
@@ -568,7 +567,7 @@
       clib_warning ("failed to attach server");
       return -1;
     }
-  if (server_listen ())
+  if (http_server_listen ())
     {
       clib_warning ("failed to start listening");
       return -1;
@@ -577,8 +576,9 @@
 }
 
 static clib_error_t *
-server_create_command_fn (vlib_main_t * vm,
-			  unformat_input_t * input, vlib_cli_command_t * cmd)
+http_server_create_command_fn (vlib_main_t * vm,
+			       unformat_input_t * input,
+			       vlib_cli_command_t * cmd)
 {
   http_server_main_t *hsm = &http_server_main;
   int rv, is_static = 0;
@@ -618,12 +618,12 @@
 
   if (is_static)
     {
-      builtin_session_cb_vft.builtin_server_rx_callback =
+      http_server_session_cb_vft.builtin_server_rx_callback =
 	http_server_rx_callback_static;
       html = format (0, html_header_static);
       static_http = format (0, http_response, vec_len (html), html);
     }
-  rv = server_create (vm);
+  rv = http_server_create (vm);
   switch (rv)
     {
     case 0:
@@ -635,16 +635,16 @@
 }
 
 /* *INDENT-OFF* */
-VLIB_CLI_COMMAND (server_create_command, static) =
+VLIB_CLI_COMMAND (http_server_create_command, static) =
 {
   .path = "test http server",
   .short_help = "test http server",
-  .function = server_create_command_fn,
+  .function = http_server_create_command_fn,
 };
 /* *INDENT-ON* */
 
 static clib_error_t *
-builtin_http_server_main_init (vlib_main_t * vm)
+http_server_main_init (vlib_main_t * vm)
 {
   http_server_main_t *hsm = &http_server_main;
   vlib_thread_main_t *vtm = vlib_get_thread_main ();
@@ -657,7 +657,7 @@
   return 0;
 }
 
-VLIB_INIT_FUNCTION (builtin_http_server_main_init);
+VLIB_INIT_FUNCTION (http_server_main_init);
 
 /*
 * fd.io coding-style-patch-verification: ON
diff --git a/src/vnet/tcp/builtin_proxy.c b/src/vnet/session-apps/proxy.c
similarity index 60%
rename from src/vnet/tcp/builtin_proxy.c
rename to src/vnet/session-apps/proxy.c
index a4827bf..2fdb63f 100644
--- a/src/vnet/tcp/builtin_proxy.c
+++ b/src/vnet/session-apps/proxy.c
@@ -17,14 +17,14 @@
 #include <vlibmemory/api.h>
 #include <vnet/session/application.h>
 #include <vnet/session/application_interface.h>
-#include <vnet/tcp/builtin_proxy.h>
+#include <vnet/session-apps/proxy.h>
 
-builtin_proxy_main_t builtin_proxy_main;
+proxy_main_t proxy_main;
 
 static void
 delete_proxy_session (stream_session_t * s, int is_active_open)
 {
-  builtin_proxy_main_t *bpm = &builtin_proxy_main;
+  proxy_main_t *pm = &proxy_main;
   proxy_session_t *ps = 0;
   vnet_disconnect_args_t _a, *a = &_a;
   stream_session_t *active_open_session = 0;
@@ -34,12 +34,12 @@
 
   handle = session_handle (s);
 
-  clib_spinlock_lock_if_init (&bpm->sessions_lock);
+  clib_spinlock_lock_if_init (&pm->sessions_lock);
   if (is_active_open)
     {
       active_open_session = s;
 
-      p = hash_get (bpm->proxy_session_by_active_open_handle, handle);
+      p = hash_get (pm->proxy_session_by_active_open_handle, handle);
       if (p == 0)
 	{
 	  clib_warning ("proxy session for %s handle %lld (%llx) AWOL",
@@ -48,7 +48,7 @@
 	}
       else
 	{
-	  ps = pool_elt_at_index (bpm->sessions, p[0]);
+	  ps = pool_elt_at_index (pm->sessions, p[0]);
 	  if (ps->vpp_server_handle != ~0)
 	    server_session = session_get_from_handle (ps->vpp_server_handle);
 	  else
@@ -59,7 +59,7 @@
     {
       server_session = s;
 
-      p = hash_get (bpm->proxy_session_by_server_handle, handle);
+      p = hash_get (pm->proxy_session_by_server_handle, handle);
       if (p == 0)
 	{
 	  clib_warning ("proxy session for %s handle %lld (%llx) AWOL",
@@ -68,7 +68,7 @@
 	}
       else
 	{
-	  ps = pool_elt_at_index (bpm->sessions, p[0]);
+	  ps = pool_elt_at_index (pm->sessions, p[0]);
 	  if (ps->vpp_server_handle != ~0)
 	    active_open_session = session_get_from_handle
 	      (ps->vpp_server_handle);
@@ -81,16 +81,16 @@
     {
       if (CLIB_DEBUG > 0)
 	memset (ps, 0xFE, sizeof (*ps));
-      pool_put (bpm->sessions, ps);
+      pool_put (pm->sessions, ps);
     }
 
-  clib_spinlock_unlock_if_init (&bpm->sessions_lock);
+  clib_spinlock_unlock_if_init (&pm->sessions_lock);
 
   if (active_open_session)
     {
       a->handle = session_handle (active_open_session);
-      a->app_index = bpm->active_open_app_index;
-      hash_unset (bpm->proxy_session_by_active_open_handle,
+      a->app_index = pm->active_open_app_index;
+      hash_unset (pm->proxy_session_by_active_open_handle,
 		  session_handle (active_open_session));
       vnet_disconnect_session (a);
     }
@@ -98,67 +98,67 @@
   if (server_session)
     {
       a->handle = session_handle (server_session);
-      a->app_index = bpm->server_app_index;
-      hash_unset (bpm->proxy_session_by_server_handle,
+      a->app_index = pm->server_app_index;
+      hash_unset (pm->proxy_session_by_server_handle,
 		  session_handle (server_session));
       vnet_disconnect_session (a);
     }
 }
 
 static int
-server_accept_callback (stream_session_t * s)
+proxy_accept_callback (stream_session_t * s)
 {
-  builtin_proxy_main_t *bpm = &builtin_proxy_main;
+  proxy_main_t *pm = &proxy_main;
 
   s->session_state = SESSION_STATE_READY;
 
-  clib_spinlock_lock_if_init (&bpm->sessions_lock);
+  clib_spinlock_lock_if_init (&pm->sessions_lock);
 
   return 0;
 }
 
 static void
-server_disconnect_callback (stream_session_t * s)
+proxy_disconnect_callback (stream_session_t * s)
 {
   delete_proxy_session (s, 0 /* is_active_open */ );
 }
 
 static void
-server_reset_callback (stream_session_t * s)
+proxy_reset_callback (stream_session_t * s)
 {
   clib_warning ("Reset session %U", format_stream_session, s, 2);
   delete_proxy_session (s, 0 /* is_active_open */ );
 }
 
 static int
-server_connected_callback (u32 app_index, u32 api_context,
-			   stream_session_t * s, u8 is_fail)
+proxy_connected_callback (u32 app_index, u32 api_context,
+			  stream_session_t * s, u8 is_fail)
 {
   clib_warning ("called...");
   return -1;
 }
 
 static int
-server_add_segment_callback (u32 client_index, const ssvm_private_t * sp)
+proxy_add_segment_callback (u32 client_index, const ssvm_private_t * sp)
 {
   clib_warning ("called...");
   return -1;
 }
 
 static int
-server_redirect_connect_callback (u32 client_index, void *mp)
+proxy_redirect_connect_callback (u32 client_index, void *mp)
 {
   clib_warning ("called...");
   return -1;
 }
 
 static int
-server_rx_callback (stream_session_t * s)
+proxy_rx_callback (stream_session_t * s)
 {
   u32 max_dequeue;
   int actual_transfer __attribute__ ((unused));
   svm_fifo_t *tx_fifo, *rx_fifo;
-  builtin_proxy_main_t *bpm = &builtin_proxy_main;
+  proxy_main_t *pm = &proxy_main;
   u32 thread_index = vlib_get_thread_index ();
   vnet_connect_args_t _a, *a = &_a;
   proxy_session_t *ps;
@@ -169,12 +169,12 @@
 
   ASSERT (s->thread_index == thread_index);
 
-  clib_spinlock_lock_if_init (&bpm->sessions_lock);
-  p = hash_get (bpm->proxy_session_by_server_handle, session_handle (s));
+  clib_spinlock_lock_if_init (&pm->sessions_lock);
+  p = hash_get (pm->proxy_session_by_server_handle, session_handle (s));
 
   if (PREDICT_TRUE (p != 0))
     {
-      clib_spinlock_unlock_if_init (&bpm->sessions_lock);
+      clib_spinlock_unlock_if_init (&pm->sessions_lock);
       active_open_tx_fifo = s->server_rx_fifo;
 
       /*
@@ -185,7 +185,7 @@
 	  evt.fifo = active_open_tx_fifo;
 	  evt.event_type = FIFO_EVENT_APP_TX;
 	  if (svm_queue_add
-	      (bpm->active_open_event_queue[thread_index], (u8 *) & evt,
+	      (pm->active_open_event_queue[thread_index], (u8 *) & evt,
 	       0 /* do wait for mutex */ ))
 	    clib_warning ("failed to enqueue tx evt");
 	}
@@ -204,30 +204,29 @@
 	return 0;
 
       actual_transfer = svm_fifo_peek (rx_fifo, 0 /* relative_offset */ ,
-				       max_dequeue,
-				       bpm->rx_buf[thread_index]);
+				       max_dequeue, pm->rx_buf[thread_index]);
 
       /* $$$ your message in this space: parse url, etc. */
 
       memset (a, 0, sizeof (*a));
 
-      clib_spinlock_lock_if_init (&bpm->sessions_lock);
-      pool_get (bpm->sessions, ps);
+      clib_spinlock_lock_if_init (&pm->sessions_lock);
+      pool_get (pm->sessions, ps);
       memset (ps, 0, sizeof (*ps));
       ps->server_rx_fifo = rx_fifo;
       ps->server_tx_fifo = tx_fifo;
       ps->vpp_server_handle = session_handle (s);
 
-      proxy_index = ps - bpm->sessions;
+      proxy_index = ps - pm->sessions;
 
-      hash_set (bpm->proxy_session_by_server_handle, ps->vpp_server_handle,
+      hash_set (pm->proxy_session_by_server_handle, ps->vpp_server_handle,
 		proxy_index);
 
-      clib_spinlock_unlock_if_init (&bpm->sessions_lock);
+      clib_spinlock_unlock_if_init (&pm->sessions_lock);
 
-      a->uri = (char *) bpm->client_uri;
+      a->uri = (char *) pm->client_uri;
       a->api_context = proxy_index;
-      a->app_index = bpm->active_open_app_index;
+      a->app_index = pm->active_open_app_index;
       a->mp = 0;
       vnet_connect_uri (a);
     }
@@ -235,21 +234,21 @@
   return 0;
 }
 
-static session_cb_vft_t builtin_session_cb_vft = {
-  .session_accept_callback = server_accept_callback,
-  .session_disconnect_callback = server_disconnect_callback,
-  .session_connected_callback = server_connected_callback,
-  .add_segment_callback = server_add_segment_callback,
-  .redirect_connect_callback = server_redirect_connect_callback,
-  .builtin_server_rx_callback = server_rx_callback,
-  .session_reset_callback = server_reset_callback
+static session_cb_vft_t proxy_session_cb_vft = {
+  .session_accept_callback = proxy_accept_callback,
+  .session_disconnect_callback = proxy_disconnect_callback,
+  .session_connected_callback = proxy_connected_callback,
+  .add_segment_callback = proxy_add_segment_callback,
+  .redirect_connect_callback = proxy_redirect_connect_callback,
+  .builtin_server_rx_callback = proxy_rx_callback,
+  .session_reset_callback = proxy_reset_callback
 };
 
 static int
 active_open_connected_callback (u32 app_index, u32 opaque,
 				stream_session_t * s, u8 is_fail)
 {
-  builtin_proxy_main_t *bpm = &builtin_proxy_main;
+  proxy_main_t *pm = &proxy_main;
   proxy_session_t *ps;
   u8 thread_index = vlib_get_thread_index ();
   session_fifo_event_t evt;
@@ -263,9 +262,9 @@
   /*
    * Setup proxy session handle.
    */
-  clib_spinlock_lock_if_init (&bpm->sessions_lock);
+  clib_spinlock_lock_if_init (&pm->sessions_lock);
 
-  ps = pool_elt_at_index (bpm->sessions, opaque);
+  ps = pool_elt_at_index (pm->sessions, opaque);
   ps->vpp_active_open_handle = session_handle (s);
 
   s->server_tx_fifo = ps->server_rx_fifo;
@@ -286,10 +285,10 @@
   s->server_tx_fifo->refcnt++;
   s->server_rx_fifo->refcnt++;
 
-  hash_set (bpm->proxy_session_by_active_open_handle,
+  hash_set (pm->proxy_session_by_active_open_handle,
 	    ps->vpp_active_open_handle, opaque);
 
-  clib_spinlock_unlock_if_init (&bpm->sessions_lock);
+  clib_spinlock_unlock_if_init (&pm->sessions_lock);
 
   /*
    * Send event for active open tx fifo
@@ -299,7 +298,7 @@
       evt.fifo = s->server_tx_fifo;
       evt.event_type = FIFO_EVENT_APP_TX;
       if (svm_queue_add
-	  (bpm->active_open_event_queue[thread_index], (u8 *) & evt,
+	  (pm->active_open_event_queue[thread_index], (u8 *) & evt,
 	   0 /* do wait for mutex */ ))
 	clib_warning ("failed to enqueue tx evt");
     }
@@ -328,7 +327,7 @@
 static int
 active_open_rx_callback (stream_session_t * s)
 {
-  builtin_proxy_main_t *bpm = &builtin_proxy_main;
+  proxy_main_t *pm = &proxy_main;
   session_fifo_event_t evt;
   svm_fifo_t *server_rx_fifo;
   u32 thread_index = vlib_get_thread_index ();
@@ -343,7 +342,7 @@
       evt.fifo = server_rx_fifo;
       evt.event_type = FIFO_EVENT_APP_TX;
       if (svm_queue_add
-	  (bpm->server_event_queue[thread_index], (u8 *) & evt,
+	  (pm->server_event_queue[thread_index], (u8 *) & evt,
 	   0 /* do wait for mutex */ ))
 	clib_warning ("failed to enqueue server rx evt");
     }
@@ -352,7 +351,7 @@
 }
 
 /* *INDENT-OFF* */
-static session_cb_vft_t builtin_clients = {
+static session_cb_vft_t active_open_clients = {
   .session_reset_callback = active_open_reset_callback,
   .session_connected_callback = active_open_connected_callback,
   .session_accept_callback = active_open_create_callback,
@@ -365,22 +364,22 @@
 static void
 create_api_loopbacks (vlib_main_t * vm)
 {
-  builtin_proxy_main_t *bpm = &builtin_proxy_main;
+  proxy_main_t *pm = &proxy_main;
   api_main_t *am = &api_main;
   vl_shmem_hdr_t *shmem_hdr;
 
   shmem_hdr = am->shmem_hdr;
-  bpm->vl_input_queue = shmem_hdr->vl_input_queue;
-  bpm->server_client_index =
-    vl_api_memclnt_create_internal ("proxy_server", bpm->vl_input_queue);
-  bpm->active_open_client_index =
-    vl_api_memclnt_create_internal ("proxy_active_open", bpm->vl_input_queue);
+  pm->vl_input_queue = shmem_hdr->vl_input_queue;
+  pm->server_client_index =
+    vl_api_memclnt_create_internal ("proxy_server", pm->vl_input_queue);
+  pm->active_open_client_index =
+    vl_api_memclnt_create_internal ("proxy_active_open", pm->vl_input_queue);
 }
 
 static int
-server_attach ()
+proxy_server_attach ()
 {
-  builtin_proxy_main_t *bpm = &builtin_proxy_main;
+  proxy_main_t *pm = &proxy_main;
   u64 options[APP_OPTIONS_N_OPTIONS];
   vnet_app_attach_args_t _a, *a = &_a;
   u32 segment_size = 512 << 20;
@@ -388,17 +387,17 @@
   memset (a, 0, sizeof (*a));
   memset (options, 0, sizeof (options));
 
-  if (bpm->private_segment_size)
-    segment_size = bpm->private_segment_size;
-  a->api_client_index = bpm->server_client_index;
-  a->session_cb_vft = &builtin_session_cb_vft;
+  if (pm->private_segment_size)
+    segment_size = pm->private_segment_size;
+  a->api_client_index = pm->server_client_index;
+  a->session_cb_vft = &proxy_session_cb_vft;
   a->options = options;
   a->options[APP_OPTIONS_SEGMENT_SIZE] = segment_size;
-  a->options[APP_OPTIONS_RX_FIFO_SIZE] = bpm->fifo_size;
-  a->options[APP_OPTIONS_TX_FIFO_SIZE] = bpm->fifo_size;
-  a->options[APP_OPTIONS_PRIVATE_SEGMENT_COUNT] = bpm->private_segment_count;
+  a->options[APP_OPTIONS_RX_FIFO_SIZE] = pm->fifo_size;
+  a->options[APP_OPTIONS_TX_FIFO_SIZE] = pm->fifo_size;
+  a->options[APP_OPTIONS_PRIVATE_SEGMENT_COUNT] = pm->private_segment_count;
   a->options[APP_OPTIONS_PREALLOC_FIFO_PAIRS] =
-    bpm->prealloc_fifos ? bpm->prealloc_fifos : 1;
+    pm->prealloc_fifos ? pm->prealloc_fifos : 1;
 
   a->options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
 
@@ -407,7 +406,7 @@
       clib_warning ("failed to attach server");
       return -1;
     }
-  bpm->server_app_index = a->app_index;
+  pm->server_app_index = a->app_index;
 
   return 0;
 }
@@ -415,23 +414,23 @@
 static int
 active_open_attach (void)
 {
-  builtin_proxy_main_t *bpm = &builtin_proxy_main;
+  proxy_main_t *pm = &proxy_main;
   vnet_app_attach_args_t _a, *a = &_a;
   u64 options[16];
 
   memset (a, 0, sizeof (*a));
   memset (options, 0, sizeof (options));
 
-  a->api_client_index = bpm->active_open_client_index;
-  a->session_cb_vft = &builtin_clients;
+  a->api_client_index = pm->active_open_client_index;
+  a->session_cb_vft = &active_open_clients;
 
   options[APP_OPTIONS_ACCEPT_COOKIE] = 0x12345678;
   options[APP_OPTIONS_SEGMENT_SIZE] = 512 << 20;
-  options[APP_OPTIONS_RX_FIFO_SIZE] = bpm->fifo_size;
-  options[APP_OPTIONS_TX_FIFO_SIZE] = bpm->fifo_size;
-  options[APP_OPTIONS_PRIVATE_SEGMENT_COUNT] = bpm->private_segment_count;
+  options[APP_OPTIONS_RX_FIFO_SIZE] = pm->fifo_size;
+  options[APP_OPTIONS_TX_FIFO_SIZE] = pm->fifo_size;
+  options[APP_OPTIONS_PRIVATE_SEGMENT_COUNT] = pm->private_segment_count;
   options[APP_OPTIONS_PREALLOC_FIFO_PAIRS] =
-    bpm->prealloc_fifos ? bpm->prealloc_fifos : 1;
+    pm->prealloc_fifos ? pm->prealloc_fifos : 1;
 
   options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN
     | APP_OPTIONS_FLAGS_IS_PROXY;
@@ -441,47 +440,47 @@
   if (vnet_application_attach (a))
     return -1;
 
-  bpm->active_open_app_index = a->app_index;
+  pm->active_open_app_index = a->app_index;
 
   return 0;
 }
 
 static int
-server_listen ()
+proxy_server_listen ()
 {
-  builtin_proxy_main_t *bpm = &builtin_proxy_main;
+  proxy_main_t *pm = &proxy_main;
   vnet_bind_args_t _a, *a = &_a;
   memset (a, 0, sizeof (*a));
-  a->app_index = bpm->server_app_index;
-  a->uri = (char *) bpm->server_uri;
+  a->app_index = pm->server_app_index;
+  a->uri = (char *) pm->server_uri;
   return vnet_bind_uri (a);
 }
 
 static int
-server_create (vlib_main_t * vm)
+proxy_server_create (vlib_main_t * vm)
 {
-  builtin_proxy_main_t *bpm = &builtin_proxy_main;
+  proxy_main_t *pm = &proxy_main;
   vlib_thread_main_t *vtm = vlib_get_thread_main ();
   u32 num_threads;
   int i;
 
-  if (bpm->server_client_index == (u32) ~ 0)
+  if (pm->server_client_index == (u32) ~ 0)
     create_api_loopbacks (vm);
 
   num_threads = 1 /* main thread */  + vtm->n_threads;
-  vec_validate (builtin_proxy_main.server_event_queue, num_threads - 1);
-  vec_validate (builtin_proxy_main.active_open_event_queue, num_threads - 1);
-  vec_validate (bpm->rx_buf, num_threads - 1);
+  vec_validate (proxy_main.server_event_queue, num_threads - 1);
+  vec_validate (proxy_main.active_open_event_queue, num_threads - 1);
+  vec_validate (pm->rx_buf, num_threads - 1);
 
   for (i = 0; i < num_threads; i++)
-    vec_validate (bpm->rx_buf[i], bpm->rcv_buffer_size);
+    vec_validate (pm->rx_buf[i], pm->rcv_buffer_size);
 
-  if (server_attach ())
+  if (proxy_server_attach ())
     {
       clib_warning ("failed to attach server app");
       return -1;
     }
-  if (server_listen ())
+  if (proxy_server_listen ())
     {
       clib_warning ("failed to start listening");
       return -1;
@@ -494,12 +493,12 @@
 
   for (i = 0; i < num_threads; i++)
     {
-      bpm->active_open_event_queue[i] =
+      pm->active_open_event_queue[i] =
 	session_manager_get_vpp_event_queue (i);
 
-      ASSERT (bpm->active_open_event_queue[i]);
+      ASSERT (pm->active_open_event_queue[i]);
 
-      bpm->server_event_queue[i] = session_manager_get_vpp_event_queue (i);
+      pm->server_event_queue[i] = session_manager_get_vpp_event_queue (i);
     }
 
   return 0;
@@ -509,27 +508,29 @@
 proxy_server_create_command_fn (vlib_main_t * vm, unformat_input_t * input,
 				vlib_cli_command_t * cmd)
 {
-  builtin_proxy_main_t *bpm = &builtin_proxy_main;
+  proxy_main_t *pm = &proxy_main;
+  char *default_server_uri = "tcp://0.0.0.0/23";
+  char *default_client_uri = "tcp://6.0.2.2/23";
   int rv;
   u64 tmp;
 
-  bpm->fifo_size = 64 << 10;
-  bpm->rcv_buffer_size = 1024;
-  bpm->prealloc_fifos = 0;
-  bpm->private_segment_count = 0;
-  bpm->private_segment_size = 0;
-  bpm->server_uri = 0;
+  pm->fifo_size = 64 << 10;
+  pm->rcv_buffer_size = 1024;
+  pm->prealloc_fifos = 0;
+  pm->private_segment_count = 0;
+  pm->private_segment_size = 0;
+  pm->server_uri = 0;
 
   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     {
-      if (unformat (input, "fifo-size %d", &bpm->fifo_size))
-	bpm->fifo_size <<= 10;
-      else if (unformat (input, "rcv-buf-size %d", &bpm->rcv_buffer_size))
+      if (unformat (input, "fifo-size %d", &pm->fifo_size))
+	pm->fifo_size <<= 10;
+      else if (unformat (input, "rcv-buf-size %d", &pm->rcv_buffer_size))
 	;
-      else if (unformat (input, "prealloc-fifos %d", &bpm->prealloc_fifos))
+      else if (unformat (input, "prealloc-fifos %d", &pm->prealloc_fifos))
 	;
       else if (unformat (input, "private-segment-count %d",
-			 &bpm->private_segment_count))
+			 &pm->private_segment_count))
 	;
       else if (unformat (input, "private-segment-size %U",
 			 unformat_memory_size, &tmp))
@@ -537,25 +538,33 @@
 	  if (tmp >= 0x100000000ULL)
 	    return clib_error_return
 	      (0, "private segment size %lld (%llu) too large", tmp, tmp);
-	  bpm->private_segment_size = tmp;
+	  pm->private_segment_size = tmp;
 	}
-      else if (unformat (input, "server-uri %s", &bpm->server_uri))
+      else if (unformat (input, "server-uri %s", &pm->server_uri))
 	;
-      else if (unformat (input, "client-uri %s", &bpm->client_uri))
+      else if (unformat (input, "client-uri %s", &pm->client_uri))
 	;
       else
 	return clib_error_return (0, "unknown input `%U'",
 				  format_unformat_error, input);
     }
 
-  if (!bpm->server_uri)
-    bpm->server_uri = format (0, "%s%c", "tcp://0.0.0.0/23", 0);
-  if (!bpm->client_uri)
-    bpm->client_uri = format (0, "%s%c", "tcp://6.0.2.2/23", 0);
+  if (!pm->server_uri)
+    {
+      clib_warning ("No server-uri provided, Using default: %s",
+		    default_server_uri);
+      pm->server_uri = format (0, "%s%c", default_server_uri, 0);
+    }
+  if (!pm->client_uri)
+    {
+      clib_warning ("No client-uri provided, Using default: %s",
+		    default_client_uri);
+      pm->client_uri = format (0, "%s%c", default_client_uri, 0);
+    }
 
-  vnet_session_enable_disable (vm, 1 /* turn on TCP, etc. */ );
+  vnet_session_enable_disable (vm, 1 /* turn on session and transport */ );
 
-  rv = server_create (vm);
+  rv = proxy_server_create (vm);
   switch (rv)
     {
     case 0:
@@ -568,7 +577,7 @@
 }
 
 /* *INDENT-OFF* */
-VLIB_CLI_COMMAND (server_create_command, static) =
+VLIB_CLI_COMMAND (proxy_create_command, static) =
 {
   .path = "test proxy server",
   .short_help = "test proxy server [server-uri <tcp://ip/port>]"
@@ -580,18 +589,18 @@
 /* *INDENT-ON* */
 
 clib_error_t *
-builtin_tcp_proxy_main_init (vlib_main_t * vm)
+proxy_main_init (vlib_main_t * vm)
 {
-  builtin_proxy_main_t *bpm = &builtin_proxy_main;
-  bpm->server_client_index = ~0;
-  bpm->active_open_client_index = ~0;
-  bpm->proxy_session_by_active_open_handle = hash_create (0, sizeof (uword));
-  bpm->proxy_session_by_server_handle = hash_create (0, sizeof (uword));
+  proxy_main_t *pm = &proxy_main;
+  pm->server_client_index = ~0;
+  pm->active_open_client_index = ~0;
+  pm->proxy_session_by_active_open_handle = hash_create (0, sizeof (uword));
+  pm->proxy_session_by_server_handle = hash_create (0, sizeof (uword));
 
   return 0;
 }
 
-VLIB_INIT_FUNCTION (builtin_tcp_proxy_main_init);
+VLIB_INIT_FUNCTION (proxy_main_init);
 
 /*
 * fd.io coding-style-patch-verification: ON
diff --git a/src/vnet/tcp/builtin_proxy.h b/src/vnet/session-apps/proxy.h
similarity index 87%
rename from src/vnet/tcp/builtin_proxy.h
rename to src/vnet/session-apps/proxy.h
index 517fd3b..4bca0a0 100644
--- a/src/vnet/tcp/builtin_proxy.h
+++ b/src/vnet/session-apps/proxy.h
@@ -15,12 +15,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#ifndef __included_builtin_proxy_h__
-#define __included_builtin_proxy_h__
+#ifndef __included_proxy_h__
+#define __included_proxy_h__
 
 #include <vnet/vnet.h>
 #include <vnet/ip/ip.h>
-#include <vnet/ethernet/ethernet.h>
 
 #include <vppinfra/hash.h>
 #include <vppinfra/error.h>
@@ -79,18 +78,11 @@
    */
   u8 is_init;
   u8 prealloc_fifos;		/**< Request fifo preallocation */
+} proxy_main_t;
 
-  /*
-   * Convenience
-   */
-  vlib_main_t *vlib_main;
-  vnet_main_t *vnet_main;
-  ethernet_main_t *ethernet_main;
-} builtin_proxy_main_t;
+extern proxy_main_t proxy_main;
 
-extern builtin_proxy_main_t builtin_proxy_main;
-
-#endif /* __included_builtin_proxy_h__ */
+#endif /* __included_proxy_h__ */
 
 /*
  * fd.io coding-style-patch-verification: ON
diff --git a/src/vnet/session/application.c b/src/vnet/session/application.c
index 13ccdd7..bd708fc 100644
--- a/src/vnet/session/application.c
+++ b/src/vnet/session/application.c
@@ -272,7 +272,9 @@
   if (!reg)
     return VNET_API_ERROR_APP_UNSUPPORTED_CFG;
 
-  if (vl_api_registration_file_index (reg) == ~0)
+  if (options[APP_OPTIONS_FLAGS] & APP_OPTIONS_FLAGS_IS_BUILTIN)
+    st = SSVM_N_SEGMENT_TYPES;
+  else if (vl_api_registration_file_index (reg) == VL_API_INVALID_FI)
     st = SSVM_SEGMENT_SHM;
 
   if (!application_verify_cfg (st))
diff --git a/src/vnet/session/application_interface.c b/src/vnet/session/application_interface.c
index f2a13be..63666a6 100644
--- a/src/vnet/session/application_interface.c
+++ b/src/vnet/session/application_interface.c
@@ -275,9 +275,8 @@
 /**
  * unformat a vnet URI
  *
- * fifo://name
- * tcp://ip46-addr:port
- * udp://ip46-addr:port
+ * transport-proto://ip46-addr:port
+ * eg. tcp://ip46-addr:port
  *
  * u8 ip46_address[16];
  * u16  port_in_host_byte_order;
@@ -293,51 +292,21 @@
 unformat_vnet_uri (unformat_input_t * input, va_list * args)
 {
   session_endpoint_t *sep = va_arg (*args, session_endpoint_t *);
-
-  if (unformat (input, "tcp://%U/%d", unformat_ip4_address, &sep->ip.ip4,
+  u32 transport_proto = 0;
+  if (unformat (input, "%U://%U/%d", unformat_transport_proto,
+		&transport_proto, unformat_ip4_address, &sep->ip.ip4,
 		&sep->port))
     {
-      sep->transport_proto = TRANSPORT_PROTO_TCP;
+      sep->transport_proto = transport_proto;
       sep->port = clib_host_to_net_u16 (sep->port);
       sep->is_ip4 = 1;
       return 1;
     }
-  if (unformat (input, "udp://%U/%d", unformat_ip4_address, &sep->ip.ip4,
+  if (unformat (input, "%U://%U/%d", unformat_transport_proto,
+		&transport_proto, unformat_ip6_address, &sep->ip.ip6,
 		&sep->port))
     {
-      sep->transport_proto = TRANSPORT_PROTO_UDP;
-      sep->port = clib_host_to_net_u16 (sep->port);
-      sep->is_ip4 = 1;
-      return 1;
-    }
-  if (unformat (input, "udp://%U/%d", unformat_ip6_address, &sep->ip.ip6,
-		&sep->port))
-    {
-      sep->transport_proto = TRANSPORT_PROTO_UDP;
-      sep->port = clib_host_to_net_u16 (sep->port);
-      sep->is_ip4 = 0;
-      return 1;
-    }
-  if (unformat (input, "tcp://%U/%d", unformat_ip6_address, &sep->ip.ip6,
-		&sep->port))
-    {
-      sep->transport_proto = TRANSPORT_PROTO_TCP;
-      sep->port = clib_host_to_net_u16 (sep->port);
-      sep->is_ip4 = 0;
-      return 1;
-    }
-  if (unformat (input, "sctp://%U/%d", unformat_ip4_address, &sep->ip.ip4,
-		&sep->port))
-    {
-      sep->transport_proto = TRANSPORT_PROTO_SCTP;
-      sep->port = clib_host_to_net_u16 (sep->port);
-      sep->is_ip4 = 1;
-      return 1;
-    }
-  if (unformat (input, "sctp://%U/%d", unformat_ip6_address, &sep->ip.ip6,
-		&sep->port))
-    {
-      sep->transport_proto = TRANSPORT_PROTO_SCTP;
+      sep->transport_proto = transport_proto;
       sep->port = clib_host_to_net_u16 (sep->port);
       sep->is_ip4 = 0;
       return 1;
diff --git a/src/vnet/session/transport.c b/src/vnet/session/transport.c
index 964e739..c31964c 100644
--- a/src/vnet/session/transport.c
+++ b/src/vnet/session/transport.c
@@ -73,6 +73,9 @@
     case TRANSPORT_PROTO_UDP:
       s = format (s, "U");
       break;
+    case TRANSPORT_PROTO_SCTP:
+      s = format (s, "S");
+      break;
     }
   return s;
 }
@@ -89,7 +92,7 @@
     *proto = TRANSPORT_PROTO_UDP;
   else if (unformat (input, "UDP"))
     *proto = TRANSPORT_PROTO_UDP;
-  if (unformat (input, "sctp"))
+  else if (unformat (input, "sctp"))
     *proto = TRANSPORT_PROTO_SCTP;
   else if (unformat (input, "SCTP"))
     *proto = TRANSPORT_PROTO_SCTP;
diff --git a/src/vnet/tcp/builtin_client.c b/src/vnet/tcp/builtin_client.c
deleted file mode 100644
index 2784591..0000000
--- a/src/vnet/tcp/builtin_client.c
+++ /dev/null
@@ -1,819 +0,0 @@
-/*
- * builtin_client.c - vpp built-in tcp client/connect code
- *
- * Copyright (c) 2017 by Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <vnet/vnet.h>
-#include <vnet/plugin/plugin.h>
-#include <vnet/tcp/builtin_client.h>
-
-#include <vlibapi/api.h>
-#include <vlibmemory/api.h>
-#include <vpp/app/version.h>
-
-tclient_main_t tclient_main;
-
-#define TCP_BUILTIN_CLIENT_DBG (0)
-
-static void
-signal_evt_to_cli_i (int *code)
-{
-  tclient_main_t *tm = &tclient_main;
-  ASSERT (vlib_get_thread_index () == 0);
-  vlib_process_signal_event (tm->vlib_main, tm->cli_node_index, *code, 0);
-}
-
-static void
-signal_evt_to_cli (int code)
-{
-  if (vlib_get_thread_index () != 0)
-    vl_api_rpc_call_main_thread (signal_evt_to_cli_i, (u8 *) & code,
-				 sizeof (code));
-  else
-    signal_evt_to_cli_i (&code);
-}
-
-static void
-send_test_chunk (tclient_main_t * tm, session_t * s)
-{
-  u8 *test_data = tm->connect_test_data;
-  int test_buf_offset;
-  u32 bytes_this_chunk;
-  session_fifo_event_t evt;
-  svm_fifo_t *txf;
-  int rv;
-
-  ASSERT (vec_len (test_data) > 0);
-
-  test_buf_offset = s->bytes_sent % vec_len (test_data);
-  bytes_this_chunk = vec_len (test_data) - test_buf_offset;
-
-  bytes_this_chunk = bytes_this_chunk < s->bytes_to_send
-    ? bytes_this_chunk : s->bytes_to_send;
-
-  txf = s->server_tx_fifo;
-  rv = svm_fifo_enqueue_nowait (txf, bytes_this_chunk,
-				test_data + test_buf_offset);
-
-  /* If we managed to enqueue data... */
-  if (rv > 0)
-    {
-      /* Account for it... */
-      s->bytes_to_send -= rv;
-      s->bytes_sent += rv;
-
-      if (TCP_BUILTIN_CLIENT_DBG)
-	{
-          /* *INDENT-OFF* */
-          ELOG_TYPE_DECLARE (e) =
-            {
-              .format = "tx-enq: xfer %d bytes, sent %u remain %u",
-              .format_args = "i4i4i4",
-            };
-          /* *INDENT-ON* */
-	  struct
-	  {
-	    u32 data[3];
-	  } *ed;
-	  ed = ELOG_DATA (&vlib_global_main.elog_main, e);
-	  ed->data[0] = rv;
-	  ed->data[1] = s->bytes_sent;
-	  ed->data[2] = s->bytes_to_send;
-	}
-
-      /* Poke the session layer */
-      if (svm_fifo_set_event (txf))
-	{
-	  /* Fabricate TX event, send to vpp */
-	  evt.fifo = txf;
-	  evt.event_type = FIFO_EVENT_APP_TX;
-
-	  if (svm_queue_add
-	      (tm->vpp_event_queue[txf->master_thread_index], (u8 *) & evt,
-	       0 /* do wait for mutex */ ))
-	    clib_warning ("could not enqueue event");
-	}
-    }
-}
-
-static void
-receive_test_chunk (tclient_main_t * tm, session_t * s)
-{
-  svm_fifo_t *rx_fifo = s->server_rx_fifo;
-  u32 my_thread_index = vlib_get_thread_index ();
-  int n_read, i;
-
-  /* Allow enqueuing of new event */
-  // svm_fifo_unset_event (rx_fifo);
-
-  if (tm->test_bytes)
-    {
-      n_read = svm_fifo_dequeue_nowait (rx_fifo,
-					vec_len (tm->rx_buf[my_thread_index]),
-					tm->rx_buf[my_thread_index]);
-    }
-  else
-    {
-      n_read = svm_fifo_max_dequeue (rx_fifo);
-      svm_fifo_dequeue_drop (rx_fifo, n_read);
-    }
-
-  if (n_read > 0)
-    {
-      if (TCP_BUILTIN_CLIENT_DBG)
-	{
-          /* *INDENT-OFF* */
-          ELOG_TYPE_DECLARE (e) =
-            {
-              .format = "rx-deq: %d bytes",
-              .format_args = "i4",
-            };
-          /* *INDENT-ON* */
-	  struct
-	  {
-	    u32 data[1];
-	  } *ed;
-	  ed = ELOG_DATA (&vlib_global_main.elog_main, e);
-	  ed->data[0] = n_read;
-	}
-
-      if (tm->test_bytes)
-	{
-	  for (i = 0; i < n_read; i++)
-	    {
-	      if (tm->rx_buf[my_thread_index][i]
-		  != ((s->bytes_received + i) & 0xff))
-		{
-		  clib_warning ("read %d error at byte %lld, 0x%x not 0x%x",
-				n_read, s->bytes_received + i,
-				tm->rx_buf[my_thread_index][i],
-				((s->bytes_received + i) & 0xff));
-		  tm->test_failed = 1;
-		}
-	    }
-	}
-      s->bytes_to_receive -= n_read;
-      s->bytes_received += n_read;
-    }
-}
-
-static uword
-builtin_client_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
-			vlib_frame_t * frame)
-{
-  tclient_main_t *tm = &tclient_main;
-  int my_thread_index = vlib_get_thread_index ();
-  session_t *sp;
-  int i;
-  int delete_session;
-  u32 *connection_indices;
-  u32 *connections_this_batch;
-  u32 nconnections_this_batch;
-
-  connection_indices = tm->connection_index_by_thread[my_thread_index];
-  connections_this_batch =
-    tm->connections_this_batch_by_thread[my_thread_index];
-
-  if ((tm->run_test == 0) ||
-      ((vec_len (connection_indices) == 0)
-       && vec_len (connections_this_batch) == 0))
-    return 0;
-
-  /* Grab another pile of connections */
-  if (PREDICT_FALSE (vec_len (connections_this_batch) == 0))
-    {
-      nconnections_this_batch =
-	clib_min (tm->connections_per_batch, vec_len (connection_indices));
-
-      ASSERT (nconnections_this_batch > 0);
-      vec_validate (connections_this_batch, nconnections_this_batch - 1);
-      clib_memcpy (connections_this_batch,
-		   connection_indices + vec_len (connection_indices)
-		   - nconnections_this_batch,
-		   nconnections_this_batch * sizeof (u32));
-      _vec_len (connection_indices) -= nconnections_this_batch;
-    }
-
-  if (PREDICT_FALSE (tm->prev_conns != tm->connections_per_batch
-		     && tm->prev_conns == vec_len (connections_this_batch)))
-    {
-      tm->repeats++;
-      tm->prev_conns = vec_len (connections_this_batch);
-      if (tm->repeats == 500000)
-	{
-	  clib_warning ("stuck clients");
-	}
-    }
-  else
-    {
-      tm->prev_conns = vec_len (connections_this_batch);
-      tm->repeats = 0;
-    }
-
-  for (i = 0; i < vec_len (connections_this_batch); i++)
-    {
-      delete_session = 1;
-
-      sp = pool_elt_at_index (tm->sessions, connections_this_batch[i]);
-
-      if (sp->bytes_to_send > 0)
-	{
-	  send_test_chunk (tm, sp);
-	  delete_session = 0;
-	}
-      if (sp->bytes_to_receive > 0)
-	{
-	  receive_test_chunk (tm, sp);
-	  delete_session = 0;
-	}
-      if (PREDICT_FALSE (delete_session == 1))
-	{
-	  u32 index, thread_index;
-	  stream_session_t *s;
-
-	  __sync_fetch_and_add (&tm->tx_total, sp->bytes_sent);
-	  __sync_fetch_and_add (&tm->rx_total, sp->bytes_received);
-
-	  session_parse_handle (sp->vpp_session_handle,
-				&index, &thread_index);
-	  s = session_get_if_valid (index, thread_index);
-
-	  if (s)
-	    {
-	      vnet_disconnect_args_t _a, *a = &_a;
-	      a->handle = session_handle (s);
-	      a->app_index = tm->app_index;
-	      vnet_disconnect_session (a);
-
-	      vec_delete (connections_this_batch, 1, i);
-	      i--;
-	      __sync_fetch_and_add (&tm->ready_connections, -1);
-	    }
-	  else
-	    clib_warning ("session AWOL?");
-
-	  /* Kick the debug CLI process */
-	  if (tm->ready_connections == 0)
-	    {
-	      signal_evt_to_cli (2);
-	    }
-	}
-    }
-
-  tm->connection_index_by_thread[my_thread_index] = connection_indices;
-  tm->connections_this_batch_by_thread[my_thread_index] =
-    connections_this_batch;
-  return 0;
-}
-
-/* *INDENT-OFF* */
-VLIB_REGISTER_NODE (builtin_client_node) =
-{
-  .function = builtin_client_node_fn,
-  .name = "builtin-tcp-client",
-  .type = VLIB_NODE_TYPE_INPUT,
-  .state = VLIB_NODE_STATE_DISABLED,
-};
-/* *INDENT-ON* */
-
-static int
-create_api_loopback (tclient_main_t * tm)
-{
-  api_main_t *am = &api_main;
-  vl_shmem_hdr_t *shmem_hdr;
-
-  shmem_hdr = am->shmem_hdr;
-  tm->vl_input_queue = shmem_hdr->vl_input_queue;
-  tm->my_client_index = vl_api_memclnt_create_internal ("tcp_test_client",
-							tm->vl_input_queue);
-  return 0;
-}
-
-static int
-tcp_test_clients_init (vlib_main_t * vm)
-{
-  tclient_main_t *tm = &tclient_main;
-  vlib_thread_main_t *vtm = vlib_get_thread_main ();
-  u32 num_threads;
-  int i;
-
-  if (create_api_loopback (tm))
-    return -1;
-
-  num_threads = 1 /* main thread */  + vtm->n_threads;
-
-  /* Init test data. Big buffer */
-  vec_validate (tm->connect_test_data, 1024 * 1024 - 1);
-  for (i = 0; i < vec_len (tm->connect_test_data); i++)
-    tm->connect_test_data[i] = i & 0xff;
-
-  vec_validate (tm->rx_buf, num_threads - 1);
-  for (i = 0; i < num_threads; i++)
-    vec_validate (tm->rx_buf[i], vec_len (tm->connect_test_data) - 1);
-
-  tm->is_init = 1;
-
-  vec_validate (tm->connection_index_by_thread, vtm->n_vlib_mains);
-  vec_validate (tm->connections_this_batch_by_thread, vtm->n_vlib_mains);
-  vec_validate (tm->vpp_event_queue, vtm->n_vlib_mains);
-
-  return 0;
-}
-
-static int
-builtin_session_connected_callback (u32 app_index, u32 api_context,
-				    stream_session_t * s, u8 is_fail)
-{
-  tclient_main_t *tm = &tclient_main;
-  session_t *session;
-  u32 session_index;
-  u8 thread_index = vlib_get_thread_index ();
-
-  if (is_fail)
-    {
-      clib_warning ("connection %d failed!", api_context);
-      signal_evt_to_cli (-1);
-      return 0;
-    }
-
-  ASSERT (s->thread_index == thread_index);
-
-  if (!tm->vpp_event_queue[thread_index])
-    tm->vpp_event_queue[thread_index] =
-      session_manager_get_vpp_event_queue (thread_index);
-
-  /*
-   * Setup session
-   */
-  clib_spinlock_lock_if_init (&tm->sessions_lock);
-  pool_get (tm->sessions, session);
-  clib_spinlock_unlock_if_init (&tm->sessions_lock);
-
-  memset (session, 0, sizeof (*session));
-  session_index = session - tm->sessions;
-  session->bytes_to_send = tm->bytes_to_send;
-  session->bytes_to_receive = tm->no_return ? 0ULL : tm->bytes_to_send;
-  session->server_rx_fifo = s->server_rx_fifo;
-  session->server_rx_fifo->client_session_index = session_index;
-  session->server_tx_fifo = s->server_tx_fifo;
-  session->server_tx_fifo->client_session_index = session_index;
-  session->vpp_session_handle = session_handle (s);
-
-  vec_add1 (tm->connection_index_by_thread[thread_index], session_index);
-  __sync_fetch_and_add (&tm->ready_connections, 1);
-  if (tm->ready_connections == tm->expected_connections)
-    {
-      tm->run_test = 1;
-      /* Signal the CLI process that the action is starting... */
-      signal_evt_to_cli (1);
-    }
-
-  return 0;
-}
-
-static void
-builtin_session_reset_callback (stream_session_t * s)
-{
-  if (s->session_state == SESSION_STATE_READY)
-    clib_warning ("Reset active connection %U", format_stream_session, s, 2);
-  stream_session_cleanup (s);
-  return;
-}
-
-static int
-builtin_session_create_callback (stream_session_t * s)
-{
-  return 0;
-}
-
-static void
-builtin_session_disconnect_callback (stream_session_t * s)
-{
-  tclient_main_t *tm = &tclient_main;
-  vnet_disconnect_args_t _a, *a = &_a;
-  a->handle = session_handle (s);
-  a->app_index = tm->app_index;
-  vnet_disconnect_session (a);
-  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 clib_error_t *
-attach_builtin_test_clients_app (u8 * appns_id, u64 appns_flags,
-				 u64 appns_secret)
-{
-  u32 prealloc_fifos, segment_size = 2 << 20;
-  tclient_main_t *tm = &tclient_main;
-  vnet_app_attach_args_t _a, *a = &_a;
-  u64 options[16];
-  clib_error_t *error = 0;
-
-  memset (a, 0, sizeof (*a));
-  memset (options, 0, sizeof (options));
-
-  a->api_client_index = tm->my_client_index;
-  a->session_cb_vft = &builtin_clients;
-
-  prealloc_fifos = tm->prealloc_fifos ? tm->expected_connections : 1;
-
-  if (tm->private_segment_size)
-    segment_size = tm->private_segment_size;
-
-  options[APP_OPTIONS_ACCEPT_COOKIE] = 0x12345678;
-  options[APP_OPTIONS_SEGMENT_SIZE] = segment_size;
-  options[APP_OPTIONS_RX_FIFO_SIZE] = tm->fifo_size;
-  options[APP_OPTIONS_TX_FIFO_SIZE] = tm->fifo_size;
-  options[APP_OPTIONS_PRIVATE_SEGMENT_COUNT] = tm->private_segment_count;
-  options[APP_OPTIONS_PREALLOC_FIFO_PAIRS] = prealloc_fifos;
-
-  options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
-  if (appns_id)
-    {
-      options[APP_OPTIONS_FLAGS] |= appns_flags;
-      options[APP_OPTIONS_NAMESPACE_SECRET] = appns_secret;
-    }
-  a->options = options;
-  a->namespace_id = appns_id;
-
-  if ((error = vnet_application_attach (a)))
-    return error;
-
-  tm->app_index = a->app_index;
-  return 0;
-}
-
-static void *
-tclient_thread_fn (void *arg)
-{
-  return 0;
-}
-
-/** Start a transmit thread */
-int
-start_tx_pthread (tclient_main_t * tm)
-{
-  if (tm->client_thread_handle == 0)
-    {
-      int rv = pthread_create (&tm->client_thread_handle,
-			       NULL /*attr */ ,
-			       tclient_thread_fn, 0);
-      if (rv)
-	{
-	  tm->client_thread_handle = 0;
-	  return -1;
-	}
-    }
-  return 0;
-}
-
-clib_error_t *
-clients_connect (vlib_main_t * vm, u8 * uri, u32 n_clients)
-{
-  tclient_main_t *tm = &tclient_main;
-  vnet_connect_args_t _a, *a = &_a;
-  clib_error_t *error = 0;
-  int i;
-  for (i = 0; i < n_clients; i++)
-    {
-      memset (a, 0, sizeof (*a));
-
-      a->uri = (char *) uri;
-      a->api_context = i;
-      a->app_index = tm->app_index;
-      a->mp = 0;
-
-      if ((error = vnet_connect_uri (a)))
-	return error;
-
-
-      /* Crude pacing for call setups  */
-      if ((i % 4) == 0)
-	vlib_process_suspend (vm, 10e-6);
-      ASSERT (i + 1 >= tm->ready_connections);
-      while (i + 1 - tm->ready_connections > 1000)
-	{
-	  vlib_process_suspend (vm, 100e-6);
-	}
-    }
-  return 0;
-}
-
-#define CLI_OUTPUT(_fmt, _args...) 			\
-  if (!tm->no_output)  					\
-    vlib_cli_output(vm, _fmt, ##_args)
-
-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;
-  vlib_thread_main_t *thread_main = vlib_get_thread_main ();
-  uword *event_data = 0, event_type;
-  u8 *default_connect_uri = (u8 *) "tcp://6.0.1.1/1234", *uri, *appns_id = 0;
-  u64 tmp, total_bytes, appns_flags = 0, appns_secret = 0;
-  f64 test_timeout = 20.0, syn_timeout = 20.0, delta;
-  f64 time_before_connects;
-  u32 n_clients = 1;
-  int preallocate_sessions = 0;
-  char *transfer_type;
-  clib_error_t *error = 0;
-  int i;
-
-  tm->bytes_to_send = 8192;
-  tm->no_return = 0;
-  tm->fifo_size = 64 << 10;
-  tm->connections_per_batch = 1000;
-  tm->private_segment_count = 0;
-  tm->private_segment_size = 0;
-  tm->no_output = 0;
-  tm->test_bytes = 0;
-  tm->test_failed = 0;
-  tm->vlib_main = vm;
-  if (thread_main->n_vlib_mains > 1)
-    clib_spinlock_init (&tm->sessions_lock);
-  vec_free (tm->connect_uri);
-
-  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
-    {
-      if (unformat (input, "nclients %d", &n_clients))
-	;
-      else if (unformat (input, "mbytes %lld", &tmp))
-	tm->bytes_to_send = tmp << 20;
-      else if (unformat (input, "gbytes %lld", &tmp))
-	tm->bytes_to_send = tmp << 30;
-      else if (unformat (input, "bytes %lld", &tm->bytes_to_send))
-	;
-      else if (unformat (input, "uri %s", &tm->connect_uri))
-	;
-      else if (unformat (input, "test-timeout %f", &test_timeout))
-	;
-      else if (unformat (input, "syn-timeout %f", &syn_timeout))
-	;
-      else if (unformat (input, "no-return"))
-	tm->no_return = 1;
-      else if (unformat (input, "fifo-size %d", &tm->fifo_size))
-	tm->fifo_size <<= 10;
-      else if (unformat (input, "private-segment-count %d",
-			 &tm->private_segment_count))
-	;
-      else if (unformat (input, "private-segment-size %U",
-			 unformat_memory_size, &tmp))
-	{
-	  if (tmp >= 0x100000000ULL)
-	    return clib_error_return
-	      (0, "private segment size %lld (%llu) too large", tmp, tmp);
-	  tm->private_segment_size = tmp;
-	}
-      else if (unformat (input, "preallocate-fifos"))
-	tm->prealloc_fifos = 1;
-      else if (unformat (input, "preallocate-sessions"))
-	preallocate_sessions = 1;
-      else
-	if (unformat (input, "client-batch %d", &tm->connections_per_batch))
-	;
-      else if (unformat (input, "appns %_%v%_", &appns_id))
-	;
-      else if (unformat (input, "all-scope"))
-	appns_flags |= (APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE
-			| APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE);
-      else if (unformat (input, "local-scope"))
-	appns_flags = APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
-      else if (unformat (input, "global-scope"))
-	appns_flags = APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
-      else if (unformat (input, "secret %lu", &appns_secret))
-	;
-      else if (unformat (input, "no-output"))
-	tm->no_output = 1;
-      else if (unformat (input, "test-bytes"))
-	tm->test_bytes = 1;
-      else
-	return clib_error_return (0, "unknown input `%U'",
-				  format_unformat_error, input);
-    }
-
-  /* Store cli process node index for signalling */
-  tm->cli_node_index = vlib_get_current_process (vm)->node_runtime.node_index;
-
-  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;
-  tm->rx_total = 0;
-  tm->tx_total = 0;
-
-  uri = default_connect_uri;
-  if (tm->connect_uri)
-    uri = tm->connect_uri;
-
-#if TCP_BUILTIN_CLIENT_PTHREAD
-  start_tx_pthread ();
-#endif
-
-  vlib_worker_thread_barrier_sync (vm);
-  vnet_session_enable_disable (vm, 1 /* turn on TCP, etc. */ );
-  vlib_worker_thread_barrier_release (vm);
-
-  if (tm->test_client_attached == 0)
-    {
-      if ((error = attach_builtin_test_clients_app (appns_id, appns_flags,
-						    appns_secret)))
-	{
-	  vec_free (appns_id);
-	  clib_error_report (error);
-	  return error;
-	}
-      vec_free (appns_id);
-    }
-  tm->test_client_attached = 1;
-
-  /* Turn on the builtin client input nodes */
-  for (i = 0; i < thread_main->n_vlib_mains; i++)
-    vlib_node_set_state (vlib_mains[i], builtin_client_node.index,
-			 VLIB_NODE_STATE_POLLING);
-
-  if (preallocate_sessions)
-    {
-      session_t *sp __attribute__ ((unused));
-      for (i = 0; i < n_clients; i++)
-	pool_get (tm->sessions, sp);
-      for (i = 0; i < n_clients; i++)
-	pool_put_index (tm->sessions, i);
-    }
-
-  /* Fire off connect requests */
-  time_before_connects = vlib_time_now (vm);
-  if ((error = clients_connect (vm, uri, n_clients)))
-    return error;
-
-  /* Park until the sessions come up, or ten seconds elapse... */
-  vlib_process_wait_for_event_or_clock (vm, syn_timeout);
-  event_type = vlib_process_get_events (vm, &event_data);
-  switch (event_type)
-    {
-    case ~0:
-      CLI_OUTPUT ("Timeout with only %d sessions active...",
-		  tm->ready_connections);
-      error = clib_error_return (0, "failed: syn timeout with %d sessions",
-				 tm->ready_connections);
-      goto cleanup;
-
-    case 1:
-      delta = vlib_time_now (vm) - time_before_connects;
-      if (delta != 0.0)
-	CLI_OUTPUT ("%d three-way handshakes in %.2f seconds %.2f/s",
-		    n_clients, delta, ((f64) n_clients) / delta);
-
-      tm->test_start_time = vlib_time_now (tm->vlib_main);
-      CLI_OUTPUT ("Test started at %.6f", tm->test_start_time);
-      break;
-
-    default:
-      CLI_OUTPUT ("unexpected event(1): %d", event_type);
-      error = clib_error_return (0, "failed: unexpected event(1): %d",
-				 event_type);
-      goto cleanup;
-    }
-
-  /* Now wait for the sessions to finish... */
-  vlib_process_wait_for_event_or_clock (vm, test_timeout);
-  event_type = vlib_process_get_events (vm, &event_data);
-  switch (event_type)
-    {
-    case ~0:
-      CLI_OUTPUT ("Timeout with %d sessions still active...",
-		  tm->ready_connections);
-      error = clib_error_return (0, "failed: timeout with %d sessions",
-				 tm->ready_connections);
-      goto cleanup;
-
-    case 2:
-      tm->test_end_time = vlib_time_now (vm);
-      CLI_OUTPUT ("Test finished at %.6f", tm->test_end_time);
-      break;
-
-    default:
-      CLI_OUTPUT ("unexpected event(2): %d", event_type);
-      error = clib_error_return (0, "failed: unexpected event(2): %d",
-				 event_type);
-      goto cleanup;
-    }
-
-  delta = tm->test_end_time - tm->test_start_time;
-
-  if (delta != 0.0)
-    {
-      total_bytes = (tm->no_return ? tm->tx_total : tm->rx_total);
-      transfer_type = tm->no_return ? "half-duplex" : "full-duplex";
-      CLI_OUTPUT ("%lld bytes (%lld mbytes, %lld gbytes) in %.2f seconds",
-		  total_bytes, total_bytes / (1ULL << 20),
-		  total_bytes / (1ULL << 30), delta);
-      CLI_OUTPUT ("%.2f bytes/second %s", ((f64) total_bytes) / (delta),
-		  transfer_type);
-      CLI_OUTPUT ("%.4f gbit/second %s",
-		  (((f64) total_bytes * 8.0) / delta / 1e9), transfer_type);
-    }
-  else
-    {
-      CLI_OUTPUT ("zero delta-t?");
-      error = clib_error_return (0, "failed: zero delta-t");
-      goto cleanup;
-    }
-
-  if (tm->test_bytes && tm->test_failed)
-    error = clib_error_return (0, "failed: test bytes");
-
-cleanup:
-  tm->run_test = 0;
-  for (i = 0; i < vec_len (tm->connection_index_by_thread); i++)
-    {
-      vec_reset_length (tm->connection_index_by_thread[i]);
-      vec_reset_length (tm->connections_this_batch_by_thread[i]);
-    }
-
-  pool_free (tm->sessions);
-
-  /* Detach the application, so we can use different fifo sizes next time */
-  if (tm->test_client_attached)
-    {
-      vnet_app_detach_args_t _da, *da = &_da;
-      int rv;
-
-      da->app_index = tm->app_index;
-      rv = vnet_application_detach (da);
-      if (rv)
-	{
-	  error = clib_error_return (0, "failed: app detach");
-	  CLI_OUTPUT ("WARNING: app detach failed...");
-	}
-      tm->test_client_attached = 0;
-      tm->app_index = ~0;
-    }
-  if (error)
-    CLI_OUTPUT ("test failed");
-  return error;
-}
-
-/* *INDENT-OFF* */
-VLIB_CLI_COMMAND (test_clients_command, static) =
-{
-  .path = "test tcp clients",
-  .short_help = "test tcp clients [nclients %d] [[m|g]bytes <bytes>] "
-      "[test-timeout <time>][syn-timeout <time>][no-return][fifo-size <size>]"
-      "[private-segment-count <count>][private-segment-size <bytes>[m|g]]"
-      "[preallocate-fifos][preallocate-sessions][client-batch <batch-size>]"
-      "[uri <tcp://ip/port>][test-bytes][no-output]",
-  .function = test_tcp_clients_command_fn,
-  .is_mp_safe = 1,
-};
-/* *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
- *
- * Local Variables:
- * eval: (c-set-style "gnu")
- * End:
- */
diff --git a/src/vnet/tcp/builtin_server.c b/src/vnet/tcp/builtin_server.c
deleted file mode 100644
index 2ea9068..0000000
--- a/src/vnet/tcp/builtin_server.c
+++ /dev/null
@@ -1,469 +0,0 @@
-/*
-* Copyright (c) 2015-2017 Cisco and/or its affiliates.
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at:
-*
-*     http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-
-#include <vnet/vnet.h>
-#include <vlibmemory/api.h>
-#include <vnet/session/application.h>
-#include <vnet/session/application_interface.h>
-
-typedef struct
-{
-  /*
-   * Server app parameters
-   */
-  svm_queue_t **vpp_queue;
-  svm_queue_t *vl_input_queue;	/**< Sever's event queue */
-
-  u32 app_index;		/**< Server app index */
-  u32 my_client_index;		/**< API client handle */
-  u32 node_index;		/**< process node index for evnt scheduling */
-
-  /*
-   * Config params
-   */
-  u8 no_echo;			/**< Don't echo traffic */
-  u32 fifo_size;			/**< Fifo size */
-  u32 rcv_buffer_size;		/**< Rcv buffer size */
-  u32 prealloc_fifos;		/**< Preallocate fifos */
-  u32 private_segment_count;	/**< Number of private segments  */
-  u32 private_segment_size;	/**< Size of private segments  */
-  char *server_uri;		/**< Server URI */
-
-  /*
-   * Test state
-   */
-  u8 **rx_buf;			/**< Per-thread RX buffer */
-  u64 byte_index;
-  u32 **rx_retries;
-
-  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)
-{
-  builtin_server_main_t *bsm = &builtin_server_main;
-
-  bsm->vpp_queue[s->thread_index] =
-    session_manager_get_vpp_event_queue (s->thread_index);
-  s->session_state = SESSION_STATE_READY;
-  bsm->byte_index = 0;
-  vec_validate (bsm->rx_retries[s->thread_index], s->session_index);
-  bsm->rx_retries[s->thread_index][s->session_index] = 0;
-  return 0;
-}
-
-void
-builtin_session_disconnect_callback (stream_session_t * s)
-{
-  builtin_server_main_t *bsm = &builtin_server_main;
-  vnet_disconnect_args_t _a, *a = &_a;
-
-  a->handle = session_handle (s);
-  a->app_index = bsm->app_index;
-  vnet_disconnect_session (a);
-}
-
-void
-builtin_session_reset_callback (stream_session_t * s)
-{
-  clib_warning ("Reset session %U", format_stream_session, s, 2);
-  stream_session_cleanup (s);
-}
-
-
-int
-builtin_session_connected_callback (u32 app_index, u32 api_context,
-				    stream_session_t * s, u8 is_fail)
-{
-  clib_warning ("called...");
-  return -1;
-}
-
-int
-builtin_add_segment_callback (u32 client_index, const ssvm_private_t * sp)
-{
-  clib_warning ("called...");
-  return -1;
-}
-
-int
-builtin_redirect_connect_callback (u32 client_index, void *mp)
-{
-  clib_warning ("called...");
-  return -1;
-}
-
-void
-test_bytes (builtin_server_main_t * bsm, int actual_transfer)
-{
-  int i;
-  u32 my_thread_id = vlib_get_thread_index ();
-
-  for (i = 0; i < actual_transfer; i++)
-    {
-      if (bsm->rx_buf[my_thread_id][i] != ((bsm->byte_index + i) & 0xff))
-	{
-	  clib_warning ("at %lld expected %d got %d", bsm->byte_index + i,
-			(bsm->byte_index + i) & 0xff,
-			bsm->rx_buf[my_thread_id][i]);
-	}
-    }
-  bsm->byte_index += actual_transfer;
-}
-
-/*
- * If no-echo, just read the data and be done with it
- */
-int
-builtin_server_rx_callback_no_echo (stream_session_t * s)
-{
-  builtin_server_main_t *bsm = &builtin_server_main;
-  u32 my_thread_id = vlib_get_thread_index ();
-  int actual_transfer;
-  svm_fifo_t *rx_fifo;
-
-  rx_fifo = s->server_rx_fifo;
-
-  do
-    {
-      actual_transfer =
-	svm_fifo_dequeue_nowait (rx_fifo, bsm->rcv_buffer_size,
-				 bsm->rx_buf[my_thread_id]);
-    }
-  while (actual_transfer > 0);
-  return 0;
-}
-
-int
-builtin_server_rx_callback (stream_session_t * s)
-{
-  u32 n_written, max_dequeue, max_enqueue, max_transfer;
-  int actual_transfer;
-  svm_fifo_t *tx_fifo, *rx_fifo;
-  builtin_server_main_t *bsm = &builtin_server_main;
-  session_fifo_event_t evt;
-  u32 thread_index = vlib_get_thread_index ();
-
-  ASSERT (s->thread_index == thread_index);
-
-  rx_fifo = s->server_rx_fifo;
-  tx_fifo = s->server_tx_fifo;
-
-  ASSERT (rx_fifo->master_thread_index == thread_index);
-  ASSERT (tx_fifo->master_thread_index == thread_index);
-
-  max_dequeue = svm_fifo_max_dequeue (s->server_rx_fifo);
-  max_enqueue = svm_fifo_max_enqueue (s->server_tx_fifo);
-
-  if (PREDICT_FALSE (max_dequeue == 0))
-    return 0;
-
-  /* Number of bytes we're going to copy */
-  max_transfer = (max_dequeue < max_enqueue) ? max_dequeue : max_enqueue;
-
-  /* No space in tx fifo */
-  if (PREDICT_FALSE (max_transfer == 0))
-    {
-      /* XXX timeout for session that are stuck */
-
-    rx_event:
-      /* Program self-tap to retry */
-      if (svm_fifo_set_event (rx_fifo))
-	{
-	  svm_queue_t *q;
-	  evt.fifo = rx_fifo;
-	  evt.event_type = FIFO_EVENT_BUILTIN_RX;
-
-	  q = bsm->vpp_queue[thread_index];
-	  if (PREDICT_FALSE (q->cursize == q->maxsize))
-	    clib_warning ("out of event queue space");
-	  else if (svm_queue_add (q, (u8 *) & evt, 0))
-	    clib_warning ("failed to enqueue self-tap");
-
-	  if (bsm->rx_retries[thread_index][s->session_index] == 500000)
-	    {
-	      clib_warning ("session stuck: %U", format_stream_session, s, 2);
-	    }
-	  if (bsm->rx_retries[thread_index][s->session_index] < 500001)
-	    bsm->rx_retries[thread_index][s->session_index]++;
-	}
-
-      return 0;
-    }
-
-  _vec_len (bsm->rx_buf[thread_index]) = max_transfer;
-
-  actual_transfer = svm_fifo_dequeue_nowait (rx_fifo, max_transfer,
-					     bsm->rx_buf[thread_index]);
-  ASSERT (actual_transfer == max_transfer);
-
-//  test_bytes (bsm, actual_transfer);
-
-  /*
-   * Echo back
-   */
-
-  n_written = svm_fifo_enqueue_nowait (tx_fifo, actual_transfer,
-				       bsm->rx_buf[thread_index]);
-
-  if (n_written != max_transfer)
-    clib_warning ("short trout!");
-
-  if (svm_fifo_set_event (tx_fifo))
-    {
-      /* Fabricate TX event, send to vpp */
-      evt.fifo = tx_fifo;
-      evt.event_type = FIFO_EVENT_APP_TX;
-
-      if (svm_queue_add (bsm->vpp_queue[s->thread_index],
-			 (u8 *) & evt, 0 /* do wait for mutex */ ))
-	clib_warning ("failed to enqueue tx evt");
-    }
-
-  if (PREDICT_FALSE (n_written < max_dequeue))
-    goto rx_event;
-
-  return 0;
-}
-
-static session_cb_vft_t builtin_session_cb_vft = {
-  .session_accept_callback = builtin_session_accept_callback,
-  .session_disconnect_callback = builtin_session_disconnect_callback,
-  .session_connected_callback = builtin_session_connected_callback,
-  .add_segment_callback = builtin_add_segment_callback,
-  .redirect_connect_callback = builtin_redirect_connect_callback,
-  .builtin_server_rx_callback = builtin_server_rx_callback,
-  .session_reset_callback = builtin_session_reset_callback
-};
-
-/* Abuse VPP's input queue */
-static int
-create_api_loopback (vlib_main_t * vm)
-{
-  builtin_server_main_t *bsm = &builtin_server_main;
-  api_main_t *am = &api_main;
-  vl_shmem_hdr_t *shmem_hdr;
-
-  shmem_hdr = am->shmem_hdr;
-  bsm->vl_input_queue = shmem_hdr->vl_input_queue;
-  bsm->my_client_index =
-    vl_api_memclnt_create_internal ("tcp_test_server", bsm->vl_input_queue);
-  return 0;
-}
-
-static int
-server_attach (u8 * appns_id, u64 appns_flags, u64 appns_secret)
-{
-  builtin_server_main_t *bsm = &builtin_server_main;
-  u64 options[APP_OPTIONS_N_OPTIONS];
-  vnet_app_attach_args_t _a, *a = &_a;
-  u32 segment_size = 512 << 20;
-
-  memset (a, 0, sizeof (*a));
-  memset (options, 0, sizeof (options));
-
-  if (bsm->no_echo)
-    builtin_session_cb_vft.builtin_server_rx_callback =
-      builtin_server_rx_callback_no_echo;
-  else
-    builtin_session_cb_vft.builtin_server_rx_callback =
-      builtin_server_rx_callback;
-
-  if (bsm->private_segment_size)
-    segment_size = bsm->private_segment_size;
-
-  a->api_client_index = bsm->my_client_index;
-  a->session_cb_vft = &builtin_session_cb_vft;
-  a->options = options;
-  a->options[APP_OPTIONS_SEGMENT_SIZE] = segment_size;
-  a->options[APP_OPTIONS_RX_FIFO_SIZE] = bsm->fifo_size;
-  a->options[APP_OPTIONS_TX_FIFO_SIZE] = bsm->fifo_size;
-  a->options[APP_OPTIONS_PRIVATE_SEGMENT_COUNT] = bsm->private_segment_count;
-  a->options[APP_OPTIONS_PREALLOC_FIFO_PAIRS] =
-    bsm->prealloc_fifos ? bsm->prealloc_fifos : 1;
-
-  a->options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
-  if (appns_id)
-    {
-      a->namespace_id = appns_id;
-      a->options[APP_OPTIONS_FLAGS] |= appns_flags;
-      a->options[APP_OPTIONS_NAMESPACE_SECRET] = appns_secret;
-    }
-
-  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 = bsm->server_uri;
-  return vnet_bind_uri (a);
-}
-
-static int
-server_create (vlib_main_t * vm, u8 * appns_id, u64 appns_flags,
-	       u64 appns_secret)
-{
-  builtin_server_main_t *bsm = &builtin_server_main;
-  vlib_thread_main_t *vtm = vlib_get_thread_main ();
-  u32 num_threads;
-  int i;
-
-  if (bsm->my_client_index == (u32) ~ 0)
-    {
-      if (create_api_loopback (vm))
-	{
-	  clib_warning ("failed to create api loopback");
-	  return -1;
-	}
-    }
-
-  num_threads = 1 /* main thread */  + vtm->n_threads;
-  vec_validate (builtin_server_main.vpp_queue, num_threads - 1);
-  vec_validate (bsm->rx_buf, num_threads - 1);
-  vec_validate (bsm->rx_retries, num_threads - 1);
-
-  for (i = 0; i < num_threads; i++)
-    vec_validate (bsm->rx_buf[i], bsm->rcv_buffer_size);
-
-  if (server_attach (appns_id, appns_flags, appns_secret))
-    {
-      clib_warning ("failed to attach server");
-      return -1;
-    }
-  if (server_listen ())
-    {
-      clib_warning ("failed to start listening");
-      return -1;
-    }
-  return 0;
-}
-
-static clib_error_t *
-server_create_command_fn (vlib_main_t * vm, unformat_input_t * input,
-			  vlib_cli_command_t * cmd)
-{
-  builtin_server_main_t *bsm = &builtin_server_main;
-  u8 server_uri_set = 0, *appns_id = 0;
-  u64 tmp, appns_flags = 0, appns_secret = 0;
-  int rv;
-
-  bsm->no_echo = 0;
-  bsm->fifo_size = 64 << 10;
-  bsm->rcv_buffer_size = 128 << 10;
-  bsm->prealloc_fifos = 0;
-  bsm->private_segment_count = 0;
-  bsm->private_segment_size = 0;
-  vec_free (bsm->server_uri);
-
-  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
-    {
-      if (unformat (input, "no-echo"))
-	bsm->no_echo = 1;
-      else if (unformat (input, "fifo-size %d", &bsm->fifo_size))
-	bsm->fifo_size <<= 10;
-      else if (unformat (input, "rcv-buf-size %d", &bsm->rcv_buffer_size))
-	;
-      else if (unformat (input, "prealloc-fifos %d", &bsm->prealloc_fifos))
-	;
-      else if (unformat (input, "private-segment-count %d",
-			 &bsm->private_segment_count))
-	;
-      else if (unformat (input, "private-segment-size %U",
-			 unformat_memory_size, &tmp))
-	{
-	  if (tmp >= 0x100000000ULL)
-	    return clib_error_return
-	      (0, "private segment size %lld (%llu) too large", tmp, tmp);
-	  bsm->private_segment_size = tmp;
-	}
-      else if (unformat (input, "uri %s", &bsm->server_uri))
-	server_uri_set = 1;
-      else if (unformat (input, "appns %_%v%_", &appns_id))
-	;
-      else if (unformat (input, "all-scope"))
-	appns_flags |= (APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE
-			| APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE);
-      else if (unformat (input, "local-scope"))
-	appns_flags |= APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
-      else if (unformat (input, "global-scope"))
-	appns_flags |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
-      else if (unformat (input, "secret %lu", &appns_secret))
-	;
-      else
-	return clib_error_return (0, "unknown input `%U'",
-				  format_unformat_error, input);
-    }
-
-  vnet_session_enable_disable (vm, 1 /* turn on TCP, etc. */ );
-
-  if (!server_uri_set)
-    bsm->server_uri = (char *) format (0, "tcp://0.0.0.0/1234%c", 0);
-
-  rv = server_create (vm, appns_id, appns_flags, appns_secret);
-  vec_free (appns_id);
-  switch (rv)
-    {
-    case 0:
-      break;
-    default:
-      return clib_error_return (0, "server_create returned %d", rv);
-    }
-
-  return 0;
-}
-
-/* *INDENT-OFF* */
-VLIB_CLI_COMMAND (server_create_command, static) =
-{
-  .path = "test tcp server",
-  .short_help = "test tcp server [no echo][fifo-size <mbytes>] "
-      "[rcv-buf-size <bytes>][prealloc-fifos <count>]"
-      "[private-segment-count <count>][private-segment-size <bytes[m|g]>]"
-      "[uri <tcp://ip/port>]",
-  .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
-*
-* Local Variables:
-* eval: (c-set-style "gnu")
-* End:
-*/
diff --git a/src/vnet/udp/builtin_server.c b/src/vnet/udp/builtin_server.c
deleted file mode 100644
index 4c9573e..0000000
--- a/src/vnet/udp/builtin_server.c
+++ /dev/null
@@ -1,277 +0,0 @@
-/*
- * Copyright (c) 2016 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/** @file
-    udp builtin server
-*/
-
-#include <vnet/udp/udp.h>
-#include <vnet/session/session.h>
-#include <vnet/session/application_interface.h>
-
-/** per-worker built-in server copy buffers */
-u8 **copy_buffers;
-static int app_index = ~0;
-
-static int
-builtin_session_create_callback (stream_session_t * s)
-{
-  /* Simple version: declare session ready-to-go... */
-  s->session_state = SESSION_STATE_READY;
-  return 0;
-}
-
-static void
-builtin_session_disconnect_callback (stream_session_t * s)
-{
-  stream_session_disconnect (s);
-}
-
-static void
-builtin_session_reset_callback (stream_session_t * s)
-{
-  clib_warning ("Reset session %U", format_stream_session, s, 2);
-  stream_session_cleanup (s);
-}
-
-static int
-builtin_session_connected_callback (u32 app_index, u32 api_context,
-				    stream_session_t * s, u8 is_fail)
-{
-  clib_warning ("called...");
-  return -1;
-}
-
-static int
-builtin_server_rx_callback (stream_session_t * s)
-{
-  svm_fifo_t *rx_fifo, *tx_fifo;
-  u32 this_transfer, max_deq, max_enq;
-  int actual_transfer;
-  u8 *my_copy_buffer;
-  session_fifo_event_t evt;
-  svm_queue_t *q;
-
-  my_copy_buffer = copy_buffers[s->thread_index];
-  rx_fifo = s->server_rx_fifo;
-  tx_fifo = s->server_tx_fifo;
-
-  max_deq = svm_fifo_max_dequeue (rx_fifo);
-  max_enq = svm_fifo_max_enqueue (tx_fifo);
-  this_transfer = max_enq < max_deq ? max_enq : max_deq;
-
-  vec_validate (my_copy_buffer, this_transfer - 1);
-  _vec_len (my_copy_buffer) = this_transfer;
-
-  actual_transfer = svm_fifo_dequeue_nowait (rx_fifo, this_transfer,
-					     my_copy_buffer);
-  ASSERT (actual_transfer == this_transfer);
-  actual_transfer = svm_fifo_enqueue_nowait (tx_fifo, this_transfer,
-					     my_copy_buffer);
-  ASSERT (actual_transfer == this_transfer);
-
-  copy_buffers[s->thread_index] = my_copy_buffer;
-
-  if (svm_fifo_set_event (tx_fifo))
-    {
-      /* Fabricate TX event, send to ourselves */
-      evt.fifo = tx_fifo;
-      evt.event_type = FIFO_EVENT_APP_TX;
-      q = session_manager_get_vpp_event_queue (s->thread_index);
-      svm_queue_add (q, (u8 *) & evt, 0 /* do wait for mutex */ );
-    }
-
-  return 0;
-}
-
-/* *INDENT-OFF* */
-static session_cb_vft_t builtin_server = {
-    .session_accept_callback = builtin_session_create_callback,
-    .session_connected_callback = builtin_session_connected_callback,
-    .session_disconnect_callback = builtin_session_disconnect_callback,
-    .builtin_server_rx_callback = builtin_server_rx_callback,
-    .session_reset_callback = builtin_session_reset_callback
-};
-/* *INDENT-ON* */
-
-static int
-attach_builtin_uri_server ()
-{
-  vnet_app_attach_args_t _a, *a = &_a;
-  u64 options[16];
-
-  memset (a, 0, sizeof (*a));
-  memset (options, 0, sizeof (options));
-
-  a->api_client_index = ~0;
-  a->session_cb_vft = &builtin_server;
-
-  options[APP_OPTIONS_ACCEPT_COOKIE] = 0x12345678;
-  options[APP_OPTIONS_SEGMENT_SIZE] = (2 << 30);	/*$$$$ config / arg */
-  options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
-  options[APP_OPTIONS_PREALLOC_FIFO_PAIRS] = 1024;
-
-  a->options = options;
-
-  if (vnet_application_attach (a))
-    return -1;
-
-  app_index = a->app_index;
-  return 0;
-}
-
-static int
-bind_builtin_uri_server (u8 * uri)
-{
-  vnet_bind_args_t _a, *a = &_a;
-  int rv;
-
-  rv = attach_builtin_uri_server ();
-  if (rv)
-    return rv;
-
-  memset (a, 0, sizeof (*a));
-  a->uri = (char *) uri;
-  a->app_index = app_index;
-
-  rv = vnet_bind_uri (a);
-
-  return rv;
-}
-
-static int
-unbind_builtin_uri_server (u8 * uri)
-{
-  vnet_unbind_args_t _a, *a = &_a;
-
-  a->app_index = app_index;
-  a->uri = (char *) uri;
-
-  return vnet_unbind_uri (a);
-}
-
-static clib_error_t *
-builtin_server_init (vlib_main_t * vm)
-{
-  vlib_thread_main_t *vtm = vlib_get_thread_main ();
-  u32 num_threads;
-
-  num_threads = 1 /* main thread */  + vtm->n_threads;
-
-  vec_validate (copy_buffers, num_threads - 1);
-  return 0;
-}
-
-VLIB_INIT_FUNCTION (builtin_server_init);
-
-static clib_error_t *
-builtin_uri_bind_command_fn (vlib_main_t * vm,
-			     unformat_input_t * input,
-			     vlib_cli_command_t * cmd)
-{
-  u8 *uri = 0;
-  int rv;
-
-  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
-    {
-      if (unformat (input, "uri %s", &uri))
-	;
-      else
-	break;
-    }
-
-  if (uri == 0)
-    return clib_error_return (0, "uri to bind not specified...");
-
-  vnet_session_enable_disable (vm, 1 /* turn on UDP, etc. */ );
-
-  rv = bind_builtin_uri_server (uri);
-
-  vec_free (uri);
-
-  switch (rv)
-    {
-    case 0:
-      break;
-
-    default:
-      return clib_error_return (0, "bind_uri_server returned %d", rv);
-      break;
-    }
-
-  return 0;
-}
-
-/* *INDENT-OFF* */
-VLIB_CLI_COMMAND (builtin_uri_bind_command, static) =
-{
-  .path = "builtin uri bind",
-  .short_help = "builtin uri bind",
-  .function = builtin_uri_bind_command_fn,
-};
-/* *INDENT-ON* */
-
-static clib_error_t *
-builtin_uri_unbind_command_fn (vlib_main_t * vm,
-			       unformat_input_t * input,
-			       vlib_cli_command_t * cmd)
-{
-  u8 *uri = 0;
-  int rv;
-
-  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
-    {
-      if (unformat (input, "uri %s", &uri))
-	;
-      else
-	break;
-    }
-
-  if (uri == 0)
-    return clib_error_return (0, "uri to unbind not specified...");
-
-  rv = unbind_builtin_uri_server (uri);
-
-  vec_free (uri);
-
-  switch (rv)
-    {
-    case 0:
-      break;
-
-    default:
-      return clib_error_return (0, "unbind_uri_server returned %d", rv);
-      break;
-    }
-
-  return 0;
-}
-
-/* *INDENT-OFF* */
-VLIB_CLI_COMMAND (builtin_uri_unbind_command, static) =
-{
-  .path = "builtin uri unbind",
-  .short_help = "builtin uri unbind",
-  .function = builtin_uri_unbind_command_fn,
-};
-/* *INDENT-ON* */
-
-/*
- * fd.io coding-style-patch-verification: ON
- *
- * Local Variables:
- * eval: (c-set-style "gnu")
- * End:
- */