summaryrefslogtreecommitdiffstats
path: root/test/test_abf.py
AgeCommit message (Expand)AuthorFilesLines
2021-05-13tests: move test source to vpp/testDave Wallace1-0/+330
2019-08-22tests: move plugin tests to src/plugins/*/testDave Wallace1-344/+0
2019-06-18fib: fib api updatesNeale Ranns1-32/+9
2019-05-16tests: refactor. Replace literal constant w/ named constant.Paul Vinciguerra1-9/+11
2019-04-10Tests Cleanup: Fix missing calls to setUpClass/tearDownClass.Paul Vinciguerra1-0/+8
2019-03-29tests: refactor vpp_object.pyPaul Vinciguerra1-6/+0
2019-03-28Typos. A bunch of typos I've been collecting.Paul Vinciguerra1-1/+1
2019-03-12FIB: path parsing, table-id not fib-index (VPP-1586)Neale Ranns1-3/+27
2019-03-01Tests: Remove all wildcard imports.Paul Vinciguerra1-6/+6
2018-09-11GBP Endpoint UpdatesNeale Ranns1-1/+2
2018-04-17ACL based forwardingAndrew Yourtchenko1-0/+338
a> 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273
/*
 * tracedump.c - skeleton vpp engine plug-in
 *
 * Copyright (c) <current-year> <your-organization>
 * 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 <tracedump/tracedump.h>
#include <vlib/trace.h>

#include <vlibapi/api.h>
#include <vlibmemory/api.h>
#include <vpp/app/version.h>
#include <stdbool.h>

#include <tracedump/tracedump.api_enum.h>
#include <tracedump/tracedump.api_types.h>

#define REPLY_MSG_ID_BASE tdmp->msg_id_base
#include <vlibapi/api_helper_macros.h>

tracedump_main_t tracedump_main;

static int
trace_cmp (void *a1, void *a2)
{
  vlib_trace_header_t **t1 = a1;
  vlib_trace_header_t **t2 = a2;
  i64 dt = t1[0]->time - t2[0]->time;
  return dt < 0 ? -1 : (dt > 0 ? +1 : 0);
}

static void
toss_client_cache (tracedump_main_t * tdmp, u32 client_index,
		   vlib_trace_header_t *** client_trace_cache)
{
  vlib_trace_header_t **th;
  int i;

  /* Across each vlib main... */
  for (i = 0; i < vec_len (client_trace_cache); i++)
    {
      th = client_trace_cache[i];
      /* Toss the thread's cached data */
      vec_free (th);
    }
  /* And toss the vector of threads */
  vec_free (client_trace_cache);
  tdmp->traces[client_index] = client_trace_cache;
}

static clib_error_t *
tracedump_cache_reaper (u32 client_index)
{
  tracedump_main_t *tdmp = &tracedump_main;
  vlib_trace_header_t ***client_trace_cache;

  /* Its likely that we won't have a cache entry */
  if (client_index >= vec_len (tdmp->traces))
    return 0;

  client_trace_cache = tdmp->traces[client_index];
  toss_client_cache (tdmp, client_index, client_trace_cache);
  return 0;
}

VL_MSG_API_REAPER_FUNCTION (tracedump_cache_reaper);

/* API message handler */
static void
vl_api_trace_dump_t_handler (vl_api_trace_dump_t * mp)
{
  vl_api_registration_t *rp;
  vl_api_trace_dump_reply_t *rmp;
  vl_api_trace_details_t *dmp;
  tracedump_main_t *tdmp = &tracedump_main;
  vlib_trace_header_t ***client_trace_cache, **th;
  int i, j;
  u32 client_index;
  u32 iterator_thread_id, iterator_position, max_records;
  i32 retval = VNET_API_ERROR_NO_SUCH_ENTRY;
  u32 last_thread_id = ~0, last_position = ~0;
  u8 last_done = 0;
  u8 last_more_this_thread = 0;
  u8 last_more_threads = 0;
  u8 *s = 0;

  rp = vl_api_client_index_to_registration (mp->client_index);
  if (rp == 0)
    return;

  /* Use the registration pool index... */
  client_index = rp->vl_api_registration_pool_index;

  vec_validate_init_empty (tdmp->traces, client_index, 0);

  client_trace_cache = tdmp->traces[client_index];

  /* Clear the per-client cache if requested */
  if (mp->clear_cache)
    {
      toss_client_cache (tdmp, client_index, client_trace_cache);
      client_trace_cache = 0;
    }

  /* Now, where were we? */
  iterator_thread_id = clib_net_to_host_u32 (mp->thread_id);
  iterator_position = clib_net_to_host_u32 (mp->position);
  max_records = clib_net_to_host_u32 (mp->max_records);

  /* Need a fresh cache for this client? */
  if (vec_len (client_trace_cache) == 0
      && (iterator_thread_id != ~0 || iterator_position != ~0))
    {
      vlib_worker_thread_barrier_sync (&vlib_global_main);

      /* Make a slot for each worker thread */
      vec_validate (client_trace_cache, vec_len (vlib_mains) - 1);
      i = 0;

      /* *INDENT-OFF* */
      foreach_vlib_main (
      ({
        vlib_trace_main_t *tm = &this_vlib_main->trace_main;

        /* Filter as directed */
        trace_apply_filter(this_vlib_main);

        pool_foreach (th, tm->trace_buffer_pool,
        ({
          vec_add1 (client_trace_cache[i], th[0]);
        }));

        /* Sort them by increasing time. */
        if (vec_len (client_trace_cache[i]))
          vec_sort_with_function (client_trace_cache[i], trace_cmp);

        i++;
      }));
      /* *INDENT-ON* */
      vlib_worker_thread_barrier_release (&vlib_global_main);
    }

  /* Save the cache, one way or the other */
  tdmp->traces[client_index] = client_trace_cache;

  for (i = iterator_thread_id; i < vec_len (client_trace_cache); i++)
    {
      for (j = iterator_position; j < vec_len (client_trace_cache[i]); j++)
	{
	  if (max_records == 0)
	    break;

	  retval = 0;
	  th = &client_trace_cache[i][j];

	  vec_reset_length (s);

	  s = format (s, "Packet %d\n%U\n\n", j + 1, format_vlib_trace,
		      &vlib_global_main, th[0]);

	  dmp = vl_msg_api_alloc (sizeof (*dmp) + vec_len (s));
	  dmp->_vl_msg_id =
	    htons (VL_API_TRACE_DETAILS + (tdmp->msg_id_base));
	  dmp->context = mp->context;
	  last_thread_id = dmp->thread_id = ntohl (i);
	  last_position = dmp->position = ntohl (j);
	  vl_api_vec_to_api_string (s, &dmp->trace_data);
	  dmp->more_threads = 0;
	  dmp->more_this_thread = 0;

	  /* Last record in the batch? */
	  if (max_records == 1)
	    {
	      /* More threads, but not more in this thread? */
	      if (j == (vec_len (client_trace_cache[i]) - 1))
		dmp->more_threads = 1;
	      else
		dmp->more_this_thread = 1;
	    }
	  /* Done, may or may not be at the end of a batch. */
	  dmp->done = 0;
	  if (i == (vec_len (client_trace_cache) - 1) &&
	      j == (vec_len (client_trace_cache[i]) - 1))
	    {
	      last_done = dmp->done = 1;
	      last_more_threads = dmp->more_threads = 0;
	      last_more_this_thread = dmp->more_this_thread = 0;
	      vl_api_send_msg (rp, (u8 *) dmp);
	      goto doublebreak;
	    }
	  last_done = dmp->done;
	  vl_api_send_msg (rp, (u8 *) dmp);

	  max_records--;
	}
      iterator_position = 0;
    }

doublebreak:;

  rmp = vl_msg_api_alloc (sizeof (*rmp));
  rmp->_vl_msg_id = htons (VL_API_TRACE_DUMP_REPLY + (tdmp->msg_id_base));
  rmp->context = mp->context;
  rmp->retval = clib_host_to_net_u32 (retval);
  rmp->last_thread_id = last_thread_id;
  rmp->last_position = last_position;
  rmp->done = last_done;
  rmp->more_this_thread = last_more_this_thread;
  rmp->more_threads = last_more_threads;

  /* Tag cleanup flushes to make life easy for the client */
  if (iterator_thread_id == ~0 && iterator_position == ~0)
    {
      rmp->retval = 0;
      rmp->done = 1;
      rmp->flush_only = 1;
    }
  vl_api_send_msg (rp, (u8 *) rmp);

  vec_free (s);
}

/* API definitions */
#include <tracedump/tracedump.api.c>

static clib_error_t *
tracedump_init (vlib_main_t * vm)
{
  tracedump_main_t *tdmp = &tracedump_main;
  api_main_t *am = vlibapi_get_main ();

  clib_error_t *error = 0;

  tdmp->vlib_main = vm;
  tdmp->vnet_main = vnet_get_main ();

  /* Add our API messages to the global name_crc hash table */
  tdmp->msg_id_base = setup_message_id_table ();

  am->is_mp_safe[tdmp->msg_id_base + VL_API_TRACE_DUMP] = 1;

  return error;
}

VLIB_INIT_FUNCTION (tracedump_init);
/* *INDENT-OFF* */
VLIB_PLUGIN_REGISTER () =
{
  .version = VPP_BUILD_VER,
  .description = "Streaming packet trace dump plugin",
};
/* *INDENT-ON* */

/*
 * fd.io coding-style-patch-verification: ON
 *
 * Local Variables:
 * eval: (c-set-style "gnu")
 * End:
 */