selog: introduce the Shared Elog plugin 58/43858/6
authorMohammed Hawari <[email protected]>
Tue, 7 Oct 2025 14:48:25 +0000 (16:48 +0200)
committerDamjan Marion <[email protected]>
Wed, 8 Oct 2025 19:15:42 +0000 (19:15 +0000)
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 <[email protected]>
MAINTAINERS
docs/spelling_wordlist.txt
src/plugins/selog/CMakeLists.txt [new file with mode: 0644]
src/plugins/selog/FEATURE.yaml [new file with mode: 0644]
src/plugins/selog/api.c [new file with mode: 0644]
src/plugins/selog/cli.c [new file with mode: 0644]
src/plugins/selog/selog.api [new file with mode: 0644]
src/plugins/selog/selog.c [new file with mode: 0644]
src/plugins/selog/selog.h [new file with mode: 0644]
src/plugins/selog/selog_shared.h [new file with mode: 0644]

index e4c766a..7b0dc9d 100644 (file)
@@ -920,3 +920,8 @@ I:  sflow
 M:     Pim van Pelt <[email protected]>
 M:     Neil McKee <[email protected]>
 F:     src/plugins/sflow/
+
+Plugin - Shared Elog
+I:     selog
+M:     Mohammed Hawari <[email protected]>
+F:     src/plugins/selog
index 4e22435..d22e625 100644 (file)
@@ -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 (file)
index 0000000..eeb8da5
--- /dev/null
@@ -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 (file)
index 0000000..f7c496a
--- /dev/null
@@ -0,0 +1,9 @@
+---
+name: selog
+maintainer: Mohammed Hawari <[email protected]>
+
+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 (file)
index 0000000..32c1206
--- /dev/null
@@ -0,0 +1,153 @@
+/* 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
diff --git a/src/plugins/selog/cli.c b/src/plugins/selog/cli.c
new file mode 100644 (file)
index 0000000..d890f9d
--- /dev/null
@@ -0,0 +1,39 @@
+/* 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
diff --git a/src/plugins/selog/selog.api b/src/plugins/selog/selog.api
new file mode 100644 (file)
index 0000000..6a3f6f5
--- /dev/null
@@ -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 (file)
index 0000000..7cce4c3
--- /dev/null
@@ -0,0 +1,81 @@
+/* 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
diff --git a/src/plugins/selog/selog.h b/src/plugins/selog/selog.h
new file mode 100644 (file)
index 0000000..c7c7529
--- /dev/null
@@ -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 <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
diff --git a/src/plugins/selog/selog_shared.h b/src/plugins/selog/selog_shared.h
new file mode 100644 (file)
index 0000000..47ef3de
--- /dev/null
@@ -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 <vppinfra/elog.h>
+typedef struct
+{
+  elog_main_t em;
+} selog_shared_header_t;
+
+#endif
\ No newline at end of file