From: Mohammed Hawari Date: Tue, 7 Oct 2025 14:48:25 +0000 (+0200) Subject: selog: introduce the Shared Elog plugin X-Git-Url: https://gerrit.fd.io/r/gitweb?a=commitdiff_plain;h=refs%2Fchanges%2F58%2F43858%2F6;p=vpp.git selog: introduce the Shared Elog plugin This plugin relies on the binary API and SSVM to expose the elog_main in shared memory Change-Id: Id6ac41ae5bd2935406f92d27969e7d129c0f2a4e Type: feature Signed-off-by: Mohammed Hawari --- diff --git a/MAINTAINERS b/MAINTAINERS index e4c766a6d28..7b0dc9d9a99 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -920,3 +920,8 @@ I: sflow M: Pim van Pelt M: Neil McKee F: src/plugins/sflow/ + +Plugin - Shared Elog +I: selog +M: Mohammed Hawari +F: src/plugins/selog diff --git a/docs/spelling_wordlist.txt b/docs/spelling_wordlist.txt index 4e22435bafa..d22e625ae16 100644 --- a/docs/spelling_wordlist.txt +++ b/docs/spelling_wordlist.txt @@ -1026,6 +1026,7 @@ seatbelt seg segfault selinux +selog semodule semver setjmp @@ -1078,6 +1079,7 @@ SRv6 sshd ssl ssm +ssvm stateful Stateful statfs diff --git a/src/plugins/selog/CMakeLists.txt b/src/plugins/selog/CMakeLists.txt new file mode 100644 index 00000000000..eeb8da5424b --- /dev/null +++ b/src/plugins/selog/CMakeLists.txt @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright (c) 2025 Cisco Systems, Inc. +# + +add_vpp_plugin(selog + SOURCES + selog.c + api.c + cli.c + + API_FILES + selog.api + + INSTALL_HEADERS + selog.h + selog_shared.h +) \ No newline at end of file diff --git a/src/plugins/selog/FEATURE.yaml b/src/plugins/selog/FEATURE.yaml new file mode 100644 index 00000000000..f7c496ad23b --- /dev/null +++ b/src/plugins/selog/FEATURE.yaml @@ -0,0 +1,9 @@ +--- +name: selog +maintainer: Mohammed Hawari + +description: |- + This plugin implements elog in shared memory over ssvm. + +state: experimental +properties: [CLI, API, MULTITHREAD] diff --git a/src/plugins/selog/api.c b/src/plugins/selog/api.c new file mode 100644 index 00000000000..32c1206fa0c --- /dev/null +++ b/src/plugins/selog/api.c @@ -0,0 +1,153 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright (c) 2025 Cisco Systems, Inc. + */ + +#include +#include +#include +#include +#include + +#define REPLY_MSG_ID_BASE selog_main.msg_id_base +#define SELOG_MAX_FORMAT_STR_SIZE (1ULL << 30) +#include + +static void +vl_api_selog_get_shm_t_handler (vl_api_selog_get_shm_t *mp) +{ + vl_api_selog_get_shm_reply_t *rmp; + selog_main_t *sm = &selog_main; + vl_api_registration_t *reg; + int rv = 0; + u32 file_index; + + reg = vl_api_client_index_to_registration (mp->client_index); + if ((file_index = vl_api_registration_file_index (reg)) == VL_API_INVALID_FI) + rv = VNET_API_ERROR_UNIMPLEMENTED; + + REPLY_MACRO (VL_API_SELOG_GET_SHM_REPLY); + if (rv == 0) + { + clib_error_t *error = vl_api_send_fd_msg (reg, &sm->ssvm.fd, 1); + if (error) + clib_error_report (error); + } +} + +static void +vl_api_selog_get_string_table_t_handler (vl_api_selog_get_string_table_t *mp) +{ + selog_main_t *sm = &selog_main; + elog_main_t *em = sm->em; + vl_api_registration_t *reg; + vl_api_selog_get_string_table_reply_t *rmp; + int rv = 0; + + reg = vl_api_client_index_to_registration (mp->client_index); + if (!reg) + return; + REPLY_MACRO3 ( + VL_API_SELOG_GET_STRING_TABLE_REPLY, vec_len (em->string_table), + { vl_api_vec_to_api_string ((u8 *) em->string_table, &rmp->s); }); +} + +static void +vl_api_selog_track_dump_t_handler (vl_api_selog_track_dump_t *mp) +{ + selog_main_t *sm = &selog_main; + elog_main_t *em = sm->em; + vl_api_selog_track_details_t *rmp; + elog_track_t *track; + + vl_api_registration_t *reg; + + reg = vl_api_client_index_to_registration (mp->client_index); + if (!reg) + return; + + vec_foreach (track, em->tracks) + { + rmp = vl_msg_api_alloc (sizeof (*rmp) + vec_len (track->name)); + clib_memset (rmp, 0, sizeof (*rmp)); + rmp->context = mp->context; + rmp->_vl_msg_id = + clib_host_to_net_u16 (VL_API_SELOG_TRACK_DETAILS + REPLY_MSG_ID_BASE); + rmp->index = clib_host_to_net_u32 (track - em->tracks); + vl_api_vec_to_api_string ((u8 *) track->name, &rmp->name); + vl_api_send_msg (reg, (u8 *) rmp); + } +} + +static void +vl_api_selog_event_type_dump_t_handler (vl_api_selog_event_type_dump_t *mp) +{ + selog_main_t *sm = &selog_main; + elog_main_t *em = sm->em; + vl_api_selog_event_type_details_t *rmp; + elog_event_type_t *event_type; + vl_api_registration_t *reg; + + reg = vl_api_client_index_to_registration (mp->client_index); + if (!reg) + return; + + vec_foreach (event_type, em->event_types) + { + rmp = vl_msg_api_alloc ( + sizeof (*rmp) + + clib_strnlen (event_type->format, SELOG_MAX_FORMAT_STR_SIZE)); + clib_memset (rmp, 0, sizeof (*rmp)); + rmp->context = mp->context; + rmp->_vl_msg_id = clib_host_to_net_u16 (VL_API_SELOG_EVENT_TYPE_DETAILS + + REPLY_MSG_ID_BASE); + rmp->index = clib_host_to_net_u32 (event_type - em->event_types); + vl_api_c_string_to_api_string (event_type->format, &rmp->fmt); + clib_strncpy ((char *) rmp->fmt_args, event_type->format_args, + sizeof (rmp->fmt_args)); + vl_api_send_msg (reg, (u8 *) rmp); + } +} + +static void +vl_api_selog_event_type_string_dump_t_handler ( + vl_api_selog_event_type_string_dump_t *mp) +{ + selog_main_t *sm = &selog_main; + elog_main_t *em = sm->em; + vl_api_registration_t *reg; + vl_api_selog_event_type_string_details_t *rmp; + elog_event_type_t *event_type; + u32 eti; + char **s; + + reg = vl_api_client_index_to_registration (mp->client_index); + if (!reg) + return; + + eti = clib_net_to_host_u32 (mp->event_type_index); + event_type = vec_elt_at_index (em->event_types, eti); + vec_foreach (s, event_type->enum_strings_vector) + { + rmp = vl_msg_api_alloc (sizeof (*rmp) + vec_len (*s)); + clib_memset (rmp, 0, sizeof (*rmp)); + rmp->context = mp->context; + rmp->_vl_msg_id = clib_host_to_net_u16 ( + VL_API_SELOG_EVENT_TYPE_STRING_DETAILS + REPLY_MSG_ID_BASE); + rmp->index = clib_host_to_net_u32 (s - event_type->enum_strings_vector); + vl_api_vec_to_api_string ((u8 *) *s, &rmp->s); + vl_api_send_msg (reg, (u8 *) rmp); + } +} + +#include +static clib_error_t * +selog_api_hookup (vlib_main_t *vm) +{ + selog_main_t *sm = &selog_main; + + sm->msg_id_base = setup_message_id_table (); + + return 0; +} + +VLIB_API_INIT_FUNCTION (selog_api_hookup); \ No newline at end of file diff --git a/src/plugins/selog/cli.c b/src/plugins/selog/cli.c new file mode 100644 index 00000000000..d890f9d2060 --- /dev/null +++ b/src/plugins/selog/cli.c @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright (c) 2025 Cisco Systems, Inc. + */ +#include + +#include +#include "selog.h" + +static clib_error_t * +selog_emit_elog_command_fn (vlib_main_t *vm, unformat_input_t *input, + vlib_cli_command_t *cmd) +{ + selog_main_t *sm = &selog_main; + elog_main_t *em = sm->em; + char *msg = 0; + + if (unformat (input, "msg %s", &msg)) + { + ELOG_TYPE_DECLARE (e) = { + .format = "selog: %s", + .format_args = "T4", + }; + struct + { + u32 msg_offset; + } *ed; + ed = ELOG_DATA (em, e); + ed->msg_offset = elog_string (em, msg); + vec_free (msg); + return 0; + } + return clib_error_return (0, "Please specify msg "); +} + +VLIB_CLI_COMMAND (selog_emit_elog_command, static) = { + .path = "selog emit-elog", + .short_help = "selog emit-elog msg ", + .function = selog_emit_elog_command_fn, +}; \ No newline at end of file diff --git a/src/plugins/selog/selog.api b/src/plugins/selog/selog.api new file mode 100644 index 00000000000..6a3f6f5a7dc --- /dev/null +++ b/src/plugins/selog/selog.api @@ -0,0 +1,50 @@ +autoreply define selog_get_shm { + u32 client_index; + u32 context; +}; + +define selog_get_string_table { + u32 client_index; + u32 context; +}; + +define selog_get_string_table_reply { + u32 context; + i32 retval; + string s[]; +}; + +define selog_track_dump { + u32 client_index; + u32 context; +}; + +define selog_track_details { + u32 context; + u32 index; + string name[]; +}; + +define selog_event_type_dump { + u32 client_index; + u32 context; +}; + +define selog_event_type_details { + u32 context; + u32 index; + string fmt_args[32]; + string fmt[]; +}; + +define selog_event_type_string_dump { + u32 client_index; + u32 context; + u32 event_type_index; +}; + +define selog_event_type_string_details { + u32 context; + u32 index; + string s[]; +}; \ No newline at end of file diff --git a/src/plugins/selog/selog.c b/src/plugins/selog/selog.c new file mode 100644 index 00000000000..7cce4c31ba7 --- /dev/null +++ b/src/plugins/selog/selog.c @@ -0,0 +1,81 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright (c) 2025 Cisco Systems, Inc. + */ + +#include +#include +#include +#include + +#define SELOG_DEFAULT_SSVM_NAME "selog_ssvm" + +static clib_error_t * +selog_init (vlib_main_t *vm) +{ + selog_main_t *sm = &selog_main; + ssvm_private_t *ssvm = &sm->ssvm; + elog_event_t *new_ring; + elog_main_t *old_em = vlib_get_elog_main (); + uword n_entries = old_em->event_ring_size; + int rv; + + if (sm->config.ssvm_name == 0) + sm->config.ssvm_name = + (u8 *) format (0, "%s%c", SELOG_DEFAULT_SSVM_NAME, 0); + + ssvm->name = sm->config.ssvm_name; + ssvm->ssvm_size = + clib_mem_get_page_size () + 2 * n_entries * sizeof (elog_event_t); + + if ((rv = ssvm_server_init_memfd (ssvm)) != 0) + return clib_error_return (0, "ssvm_server_init_memfd failed: %d", rv); + + sm->shr = + clib_mem_heap_alloc (ssvm->sh->heap, sizeof (selog_shared_header_t)); + clib_memset (sm->shr, 0, sizeof (selog_shared_header_t)); + sm->em = &sm->shr->em; + /* Copy existing elog_main as is in shared memory */ + clib_memcpy (sm->em, old_em, sizeof (elog_main_t)); + + /* Create a ring buffer in the shared heap */ + new_ring = + vec_new_heap (elog_event_t, vec_len (sm->em->event_ring), ssvm->sh->heap); + + /* Copy existing events */ + clib_memcpy (new_ring, sm->em->event_ring, + vec_len (sm->em->event_ring) * sizeof (elog_event_t)); + + vec_free (sm->em->event_ring); + sm->em->event_ring = new_ring; + /* opaque[0] contains the offset to reach the selog_shared_header */ + ssvm->sh->opaque[0] = (void *) ((void *) sm->shr - (void *) ssvm->sh); + vlib_update_elog_main (sm->em); + clib_mem_free (old_em); + clib_atomic_store_rel_n (&ssvm->sh->ready, 1); + return 0; +} +VLIB_INIT_FUNCTION (selog_init); + +static clib_error_t * +selog_config (vlib_main_t *vm, unformat_input_t *input) +{ + selog_main_t *sm = &selog_main; + selog_config_t *config = &sm->config; + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "ssvm-name %s", &config->ssvm_name)) + ; + else + { + return clib_error_return (0, "Invalid selog config"); + } + } + return 0; +} +VLIB_CONFIG_FUNCTION (selog_config, "selog"); + +VLIB_PLUGIN_REGISTER () = { + .version = VPP_BUILD_VER, + .description = "sFlow random packet sampling", +}; +selog_main_t selog_main; \ No newline at end of file diff --git a/src/plugins/selog/selog.h b/src/plugins/selog/selog.h new file mode 100644 index 00000000000..c7c75296bdc --- /dev/null +++ b/src/plugins/selog/selog.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright (c) 2025 Cisco Systems, Inc. + */ + +#ifndef __included_selog_h__ +#define __included_selog_h__ + +#include +#include +#include +#include "selog_shared.h" +typedef struct +{ + u8 *ssvm_name; +} selog_config_t; +typedef struct +{ + elog_main_t *em; + ssvm_private_t ssvm; + selog_config_t config; + selog_shared_header_t *shr; + u16 msg_id_base; +} selog_main_t; + +extern selog_main_t selog_main; +#endif /* __included_selog_h__ */ \ No newline at end of file diff --git a/src/plugins/selog/selog_shared.h b/src/plugins/selog/selog_shared.h new file mode 100644 index 00000000000..47ef3de25b2 --- /dev/null +++ b/src/plugins/selog/selog_shared.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright (c) 2025 Cisco Systems, Inc. + */ + +#ifndef __included_selog_shared_h__ +#define __included_selog_shared_h__ +#include +typedef struct +{ + elog_main_t em; +} selog_shared_header_t; + +#endif \ No newline at end of file