misc: add tracedump API plugin
Type: feature Signed-off-by: Dave Barach <dave@barachs.net> Change-Id: I586547508003b95eaa74e18e4a5ac6f72986822c
This commit is contained in:
committed by
Damjan Marion
parent
ac0326fc5a
commit
65b65a4692
@@ -0,0 +1,28 @@
|
||||
|
||||
# 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.
|
||||
|
||||
add_vpp_plugin(tracedump
|
||||
SOURCES
|
||||
tracedump.c
|
||||
tracedump.h
|
||||
|
||||
API_FILES
|
||||
tracedump.api
|
||||
|
||||
API_TEST_SOURCES
|
||||
tracedump_test.c
|
||||
)
|
||||
|
||||
# API_TEST_SOURCES
|
||||
# tracedump_test.c
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* tracedump.api - streaming packet trace dump API
|
||||
*
|
||||
* Copyright (c) 2020 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 tracedump.api
|
||||
* @brief VPP control-plane API messages.
|
||||
*
|
||||
* This file defines VPP control-plane binary API messages which are generally
|
||||
* called through a shared memory interface.
|
||||
*/
|
||||
|
||||
/* Version and type recitations */
|
||||
|
||||
option version = "0.1.0";
|
||||
|
||||
service {
|
||||
rpc trace_dump returns trace_dump_reply
|
||||
stream trace_details;
|
||||
};
|
||||
|
||||
define trace_dump {
|
||||
/* Client identifier, set from api_main.my_client_index */
|
||||
u32 client_index;
|
||||
|
||||
/* Arbitrary context, so client can match reply to request */
|
||||
u32 context;
|
||||
|
||||
/* Dispose of any cached data before we begin */
|
||||
u8 clear_cache;
|
||||
|
||||
/* iterator positions, both ~0 to just clear the cache */
|
||||
u32 thread_id;
|
||||
u32 position;
|
||||
|
||||
/* Max number of replies per burst */
|
||||
u32 max_records;
|
||||
};
|
||||
|
||||
define trace_dump_reply {
|
||||
u32 context;
|
||||
i32 retval;
|
||||
u32 last_thread_id;
|
||||
u32 last_position;
|
||||
u8 more_this_thread;
|
||||
u8 more_threads;
|
||||
u8 flush_only;
|
||||
u8 done;
|
||||
};
|
||||
|
||||
define trace_details {
|
||||
/* Client identifier, set from api_main.my_client_index */
|
||||
u32 client_index;
|
||||
|
||||
/* Arbitrary context, so client can match reply to request */
|
||||
u32 context;
|
||||
|
||||
/* Position in the cache of this record */
|
||||
u32 thread_id;
|
||||
u32 position;
|
||||
|
||||
/* More or not */
|
||||
u8 more_this_thread;
|
||||
u8 more_threads;
|
||||
/* Needed when set ends in the middle of a batch */
|
||||
u8 done;
|
||||
|
||||
string trace_data[];
|
||||
};
|
||||
@@ -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:
|
||||
*/
|
||||
@@ -0,0 +1,55 @@
|
||||
|
||||
/*
|
||||
* tracedump.h - skeleton vpp engine plug-in header file
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef __included_tracedump_h__
|
||||
#define __included_tracedump_h__
|
||||
|
||||
#include <vnet/vnet.h>
|
||||
#include <vnet/ip/ip.h>
|
||||
#include <vnet/ethernet/ethernet.h>
|
||||
|
||||
#include <vppinfra/hash.h>
|
||||
#include <vppinfra/error.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/* API message ID base */
|
||||
u16 msg_id_base;
|
||||
|
||||
/*
|
||||
* cached reply data
|
||||
* traces [client_id][thread_id][trace]
|
||||
*/
|
||||
vlib_trace_header_t ****traces;
|
||||
|
||||
/* convenience */
|
||||
vlib_main_t *vlib_main;
|
||||
vnet_main_t *vnet_main;
|
||||
ethernet_main_t *ethernet_main;
|
||||
} tracedump_main_t;
|
||||
|
||||
extern tracedump_main_t tracedump_main;
|
||||
|
||||
#endif /* __included_tracedump_h__ */
|
||||
|
||||
/*
|
||||
* fd.io coding-style-patch-verification: ON
|
||||
*
|
||||
* Local Variables:
|
||||
* eval: (c-set-style "gnu")
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* tracedump.c - tracedump vpp-api-test 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 <vat/vat.h>
|
||||
#include <vlibapi/api.h>
|
||||
#include <vlibmemory/api.h>
|
||||
#include <vppinfra/error.h>
|
||||
#include <vnet/api_errno.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define __plugin_msg_base tracedump_test_main.msg_id_base
|
||||
#include <vlibapi/vat_helper_macros.h>
|
||||
|
||||
/* Declare message IDs */
|
||||
#include <tracedump/tracedump.api_enum.h>
|
||||
#include <tracedump/tracedump.api_types.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/* API message ID base */
|
||||
u16 msg_id_base;
|
||||
vat_main_t *vat_main;
|
||||
} tracedump_test_main_t;
|
||||
|
||||
tracedump_test_main_t tracedump_test_main;
|
||||
|
||||
static void
|
||||
vl_api_trace_details_t_handler (vl_api_trace_details_t * dmp)
|
||||
{
|
||||
u32 thread_id, position;
|
||||
|
||||
thread_id = clib_net_to_host_u32 (dmp->thread_id);
|
||||
position = clib_net_to_host_u32 (dmp->position);
|
||||
fformat
|
||||
(stdout,
|
||||
"thread %d position %d more_this_thread %d more_threads %d done %d\n",
|
||||
thread_id, position, (u32) dmp->more_this_thread,
|
||||
(u32) dmp->more_threads, (u32) dmp->done);
|
||||
fformat (stdout, " %U\n", vl_api_format_string, (&dmp->trace_data));
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
vl_api_trace_dump_reply_t_handler (vl_api_trace_dump_reply_t * rmp)
|
||||
{
|
||||
tracedump_test_main_t *ttm = &tracedump_test_main;
|
||||
vat_main_t *vam = ttm->vat_main;
|
||||
vl_api_trace_dump_t *mp;
|
||||
i32 retval = (i32) clib_net_to_host_u32 (rmp->retval);
|
||||
u32 thread_id, position;
|
||||
|
||||
if (retval != 0 || rmp->done)
|
||||
{
|
||||
vam->result_ready = 1;
|
||||
vam->retval = retval;
|
||||
|
||||
/* Clear the cache */
|
||||
if (retval == 0 && rmp->flush_only == 0)
|
||||
{
|
||||
M (TRACE_DUMP, mp);
|
||||
mp->clear_cache = 1;
|
||||
mp->thread_id = 0xFFFFFFFF;
|
||||
mp->position = 0xFFFFFFFF;
|
||||
S (mp);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Figure out where the next batch starts */
|
||||
thread_id = clib_host_to_net_u32 (rmp->last_thread_id);
|
||||
position = clib_host_to_net_u32 (rmp->last_position);
|
||||
|
||||
if (rmp->more_threads)
|
||||
{
|
||||
position = 0;
|
||||
thread_id++;
|
||||
}
|
||||
else
|
||||
position++;
|
||||
|
||||
M (TRACE_DUMP, mp);
|
||||
mp->clear_cache = 0;
|
||||
mp->thread_id = clib_host_to_net_u32 (thread_id);
|
||||
mp->position = clib_host_to_net_u32 (position);
|
||||
mp->max_records = clib_host_to_net_u32 (10);
|
||||
S (mp);
|
||||
}
|
||||
|
||||
static int
|
||||
api_trace_dump (vat_main_t * vam)
|
||||
{
|
||||
vl_api_trace_dump_t *mp;
|
||||
int ret;
|
||||
|
||||
M (TRACE_DUMP, mp);
|
||||
mp->clear_cache = 1;
|
||||
mp->thread_id = 0;
|
||||
mp->position = 0;
|
||||
mp->max_records = clib_host_to_net_u32 (10);
|
||||
|
||||
S (mp);
|
||||
|
||||
W (ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
|
||||
#define vl_endianfun
|
||||
#include <tracedump/tracedump.api.h>
|
||||
#undef vl_endianfun
|
||||
#define vl_printfun
|
||||
#include <tracedump/tracedump.api.h>
|
||||
#undef vl_printfun
|
||||
|
||||
void
|
||||
manual_setup_message_id_table (vat_main_t * vam)
|
||||
{
|
||||
vl_msg_api_set_handlers (VL_API_TRACE_DETAILS
|
||||
+ tracedump_test_main.msg_id_base, "trace_details",
|
||||
vl_api_trace_details_t_handler, vl_noop_handler,
|
||||
vl_api_trace_details_t_endian,
|
||||
vl_api_trace_details_t_print,
|
||||
sizeof (vl_api_trace_details_t), 1);
|
||||
}
|
||||
|
||||
#define VL_API_LOCAL_SETUP_MESSAGE_ID_TABLE manual_setup_message_id_table
|
||||
#define VL_API_TRACE_DUMP_REPLY_T_HANDLER
|
||||
|
||||
#include <tracedump/tracedump.api_test.c>
|
||||
|
||||
/*
|
||||
* fd.io coding-style-patch-verification: ON
|
||||
*
|
||||
* Local Variables:
|
||||
* eval: (c-set-style "gnu")
|
||||
* End:
|
||||
*/
|
||||
@@ -112,6 +112,8 @@ typedef struct
|
||||
|
||||
format_function_t format_vlib_trace;
|
||||
|
||||
void trace_apply_filter (struct vlib_main_t *vm);
|
||||
|
||||
#endif /* included_vlib_trace_h */
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user