syntax = "proto3";

package envoy.extensions.dynamic_modules.v3;

import "envoy/config/core/v3/base.proto";

import "udpa/annotations/status.proto";

option java_package = "io.envoyproxy.envoy.extensions.dynamic_modules.v3";
option java_outer_classname = "DynamicModulesProto";
option java_multiple_files = true;
option go_package = "github.com/envoyproxy/go-control-plane/envoy/extensions/dynamic_modules/v3;dynamic_modulesv3";
option (udpa.annotations.file_status).package_version_status = ACTIVE;

// [#protodoc-title: Dynamic Modules Common Configuration]

// Configuration of a dynamic module. A dynamic module is a shared object file that can be loaded via
// ``dlopen`` by various Envoy extension points.
//
// How a module is loaded is determined by the extension point that uses it. For example, the HTTP
// filter loads the module when Envoy receives a configuration that references the module. If loading
// the module fails, the configuration will be rejected.
//
// A module is uniquely identified by its file path and the file's inode, depending on the platform.
// Notably, if the file path and the content of the file are the same, the shared object will be
// reused.
//
// A module must be compatible with the ABI specified in :repo:`abi.h
// <source/extensions/dynamic_modules/abi/abi.h>`. Currently, compatibility is only guaranteed by an
// exact version match between the Envoy codebase and the dynamic module SDKs. In the future, after
// the ABI is stabilized, this restriction will be revisited. Until then, Envoy checks the hash of
// the ABI header files to ensure that the dynamic modules are built against the same version of the
// ABI.
// [#next-free-field: 8]
message DynamicModuleConfig {
  // The name of the dynamic module.
  //
  // The client is expected to have some configuration indicating where to search for the module. In
  // Envoy, the search path can be configured via the environment variable
  // ``ENVOY_DYNAMIC_MODULES_SEARCH_PATH``. The actual search path is
  // ``${ENVOY_DYNAMIC_MODULES_SEARCH_PATH}/lib${name}.so``. If not set, the current working directory is
  // used as the search path. After Envoy fails to find the module in the search path, it will also
  // try to find the module from a standard system library path (e.g., ``/usr/lib``) following the
  // platform's default behavior for ``dlopen``.
  //
  // This field is optional if the ``module`` field is set. When both ``name`` and ``module`` are
  // specified, the ``module`` field takes precedence.
  //
  // .. note::
  //   There is some remaining work to make the search path configurable via command line options.
  string name = 1;

  // If true, prevents the module from being unloaded with ``dlclose``.
  //
  // This is useful for modules that have global state that should not be unloaded. A module is
  // closed when no more references to it exist in the process. For example, no HTTP filters are
  // using the module (e.g. after configuration update).
  //
  // Defaults to ``false``.
  bool do_not_close = 3;

  // If ``true``, the dynamic module is loaded with the ``RTLD_GLOBAL`` flag.
  //
  // The dynamic module is loaded with the ``RTLD_LOCAL`` flag by default to avoid symbol conflicts
  // when multiple modules are loaded. Set this to ``true`` to load the module with the
  // ``RTLD_GLOBAL`` flag. This is useful for modules that need to share symbols with other dynamic
  // libraries. For example, a module X may load another shared library Y that depends on some
  // symbols defined in module X. In this case, module X must be loaded with the ``RTLD_GLOBAL``
  // flag so that the symbols defined in module X are visible to library Y.
  //
  // .. warning::
  //   Use this option with caution as it may lead to symbol conflicts and undefined behavior if
  //   multiple modules define the same symbols and are loaded globally.
  //
  // Defaults to ``false``.
  bool load_globally = 4;

  // The namespace prefix for metrics emitted by this dynamic module.
  //
  // This allows users to customize the prefix used for all metrics created by the dynamic module.
  // The prefix is prepended to all metric names. In prometheus output, metrics will appear with
  // the standard ``envoy_`` prefix followed by this namespace. For example, if this is set to
  // ``myapp``, a counter ``requests`` would appear as ``envoy_myapp_requests_total``.
  //
  // Defaults to ``dynamicmodulescustom``.
  string metrics_namespace = 5;

  // The dynamic module binary to load. Supports local file paths via ``local.filename``
  // and remote HTTP sources via ``remote``.
  //
  // When using ``remote``, the module is fetched asynchronously during listener initialization.
  // If the fetch fails (network error, SHA256 mismatch, invalid binary, etc.), the filter
  // is **not installed** and requests pass through unfiltered (fail-open).
  //
  // When both ``name`` and ``module`` are set, ``module`` takes precedence.
  config.core.v3.AsyncDataSource module = 6;

  // Controls how a cache miss for a remote module is handled.
  //
  // When true (NACK mode), a cache miss causes an immediate NACK of the xDS config update.
  // A background fetch is started and the module will be available on the next config push if
  // the fetch succeeds.
  //
  // When false (default, warming mode), the server blocks during initialization until the fetch
  // completes or exhausts retries. This mode requires an init manager and is not available in
  // ECDS or per-route configurations.
  //
  // When using ``module.remote`` with ECDS or per-route configurations, this must be set to
  // ``true``.
  //
  // Only applies when ``module.remote`` is set.
  //
  // Defaults to ``false``.
  bool nack_on_cache_miss = 7;
}
