diff options
author | Dave Barach <dave@barachs.net> | 2020-07-07 17:33:38 -0400 |
---|---|---|
committer | Damjan Marion <dmarion@me.com> | 2020-07-16 21:39:50 +0000 |
commit | 65b65a4692c84462ecf500806795ea0350073e18 (patch) | |
tree | 7c502a71b7ab710d0b6bc1448c78f1ade0f4392b /src/plugins/tracedump/tracedump.c | |
parent | ac0326fc5ae7ac4a8126bbc2f496a92fcfe4755e (diff) |
misc: add tracedump API plugin
Type: feature
Signed-off-by: Dave Barach <dave@barachs.net>
Change-Id: I586547508003b95eaa74e18e4a5ac6f72986822c
Diffstat (limited to 'src/plugins/tracedump/tracedump.c')
-rw-r--r-- | src/plugins/tracedump/tracedump.c | 256 |
1 files changed, 256 insertions, 0 deletions
diff --git a/src/plugins/tracedump/tracedump.c b/src/plugins/tracedump/tracedump.c new file mode 100644 index 00000000000..87e6cf6ac5f --- /dev/null +++ b/src/plugins/tracedump/tracedump.c @@ -0,0 +1,256 @@ +/* + * 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; +} + +/* 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: + */ |