F: src/plugins/sflow/
+
+Plugin - Shared Elog
+I: selog
+F: src/plugins/selog
seg
segfault
selinux
+selog
semodule
semver
setjmp
sshd
ssl
ssm
+ssvm
stateful
Stateful
statfs
--- /dev/null
+# 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
--- /dev/null
+---
+name: selog
+
+description: |-
+ This plugin implements elog in shared memory over ssvm.
+
+state: experimental
+properties: [CLI, API, MULTITHREAD]
--- /dev/null
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright (c) 2025 Cisco Systems, Inc.
+ */
+
+#include <vlibmemory/api.h>
+#include <vnet/api_errno.h>
+#include <selog/selog.h>
+#include <selog/selog.api_enum.h>
+#include <selog/selog.api_types.h>
+
+#define REPLY_MSG_ID_BASE selog_main.msg_id_base
+#define SELOG_MAX_FORMAT_STR_SIZE (1ULL << 30)
+#include <vlibapi/api_helper_macros.h>
+
+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 <selog/selog.api.c>
+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
--- /dev/null
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright (c) 2025 Cisco Systems, Inc.
+ */
+#include <vlib/vlib.h>
+
+#include <vlib/cli.h>
+#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 <string>");
+}
+
+VLIB_CLI_COMMAND (selog_emit_elog_command, static) = {
+ .path = "selog emit-elog",
+ .short_help = "selog emit-elog msg <string>",
+ .function = selog_emit_elog_command_fn,
+};
\ No newline at end of file
--- /dev/null
+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
--- /dev/null
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright (c) 2025 Cisco Systems, Inc.
+ */
+
+#include <vlib/vlib.h>
+#include <vlib/unix/plugin.h>
+#include <vpp/app/version.h>
+#include <selog/selog.h>
+
+#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
--- /dev/null
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright (c) 2025 Cisco Systems, Inc.
+ */
+
+#ifndef __included_selog_h__
+#define __included_selog_h__
+
+#include <vppinfra/elog.h>
+#include <vppinfra/file.h>
+#include <svm/ssvm.h>
+#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
--- /dev/null
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright (c) 2025 Cisco Systems, Inc.
+ */
+
+#ifndef __included_selog_shared_h__
+#define __included_selog_shared_h__
+#include <vppinfra/elog.h>
+typedef struct
+{
+ elog_main_t em;
+} selog_shared_header_t;
+
+#endif
\ No newline at end of file