syntax = "proto3";

package envoy.extensions.load_balancing_policies.common.v3;

import "envoy/config/core/v3/base.proto";
import "envoy/config/route/v3/route_components.proto";
import "envoy/type/v3/percent.proto";

import "google/protobuf/duration.proto";
import "google/protobuf/struct.proto";
import "google/protobuf/wrappers.proto";

import "envoy/annotations/deprecation.proto";
import "udpa/annotations/status.proto";
import "validate/validate.proto";

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

// [#protodoc-title: Common configuration for two or more load balancing policy extensions]

message LocalityLbConfig {
  // Configuration for :ref:`zone aware routing
  // <arch_overview_load_balancing_zone_aware_routing>`.
  // [#next-free-field: 7]
  message ZoneAwareLbConfig {
    // Basis for computing per-locality percentages in zone-aware routing.
    enum LocalityBasis {
      // Use the number of healthy hosts in each locality.
      HEALTHY_HOSTS_NUM = 0;

      // Use the weights of healthy hosts in each locality.
      HEALTHY_HOSTS_WEIGHT = 1;
    }

    // Configures Envoy to always route requests to the local zone regardless of the
    // upstream zone structure. In Envoy's default configuration, traffic is distributed proportionally
    // across all upstream hosts while trying to maximize local routing when possible. The approach
    // with force_local_zone aims to be more predictable and if there are upstream hosts in the local
    // zone, they will receive all traffic.
    // * :ref:`runtime values <config_cluster_manager_cluster_runtime_zone_routing>`.
    // * :ref:`Zone aware routing support <arch_overview_load_balancing_zone_aware_routing>`.
    message ForceLocalZone {
      // Configures the minimum number of upstream hosts in the local zone required when force_local_zone
      // is enabled. If the number of upstream hosts in the local zone is less than the specified value,
      // Envoy will fall back to the default proportional-based distribution across localities.
      // If not specified, the default is 1.
      // * :ref:`runtime values <config_cluster_manager_cluster_runtime_zone_routing>`.
      // * :ref:`Zone aware routing support <arch_overview_load_balancing_zone_aware_routing>`.
      google.protobuf.UInt32Value min_size = 1;
    }

    // Configures percentage of requests that will be considered for zone aware routing
    // if zone aware routing is configured. If not specified, the default is 100%.
    // * :ref:`runtime values <config_cluster_manager_cluster_runtime_zone_routing>`.
    // * :ref:`Zone aware routing support <arch_overview_load_balancing_zone_aware_routing>`.
    type.v3.Percent routing_enabled = 1;

    // Configures minimum upstream cluster size required for zone aware routing
    // If upstream cluster size is less than specified, zone aware routing is not performed
    // even if zone aware routing is configured. If not specified, the default is 6.
    // * :ref:`runtime values <config_cluster_manager_cluster_runtime_zone_routing>`.
    // * :ref:`Zone aware routing support <arch_overview_load_balancing_zone_aware_routing>`.
    google.protobuf.UInt64Value min_cluster_size = 2;

    // If set to true, Envoy will not consider any hosts when the cluster is in :ref:`panic
    // mode<arch_overview_load_balancing_panic_threshold>`. Instead, the cluster will fail all
    // requests as if all hosts are unhealthy. This can help avoid potentially overwhelming a
    // failing service.
    bool fail_traffic_on_panic = 3;

    // If set to true, Envoy will force LocalityDirect routing if a local locality exists.
    bool force_locality_direct_routing = 4
        [deprecated = true, (envoy.annotations.deprecated_at_minor_version) = "3.0"];

    ForceLocalZone force_local_zone = 5;

    // Determines how locality percentages are computed:
    // - HEALTHY_HOSTS_NUM: proportional to the count of healthy hosts.
    // - HEALTHY_HOSTS_WEIGHT: proportional to the weights of healthy hosts.
    // Default value is HEALTHY_HOSTS_NUM if unset.
    LocalityBasis locality_basis = 6;
  }

  // Configuration for :ref:`locality weighted load balancing
  // <arch_overview_load_balancing_locality_weighted_lb>`
  message LocalityWeightedLbConfig {
  }

  oneof locality_config_specifier {
    option (validate.required) = true;

    // Configuration for local zone aware load balancing.
    ZoneAwareLbConfig zone_aware_lb_config = 1;

    // Enable locality weighted load balancing.
    LocalityWeightedLbConfig locality_weighted_lb_config = 2;
  }
}

// Configuration for :ref:`slow start mode <arch_overview_load_balancing_slow_start>`.
message SlowStartConfig {
  // Represents the size of slow start window.
  // If set, the newly created host remains in slow start mode starting from its creation time
  // for the duration of slow start window.
  google.protobuf.Duration slow_start_window = 1;

  // This parameter controls the speed of traffic increase over the slow start window. Defaults to 1.0,
  // so that endpoint would get linearly increasing amount of traffic.
  // When increasing the value for this parameter, the speed of traffic ramp-up increases non-linearly.
  // The value of aggression parameter should be greater than 0.0.
  // By tuning the parameter, is possible to achieve polynomial or exponential shape of ramp-up curve.
  //
  // During slow start window, effective weight of an endpoint would be scaled with time factor and aggression:
  // ``new_weight = weight * max(min_weight_percent, time_factor ^ (1 / aggression))``,
  // where ``time_factor=(time_since_start_seconds / slow_start_time_seconds)``.
  //
  // As time progresses, more and more traffic would be sent to endpoint, which is in slow start window.
  // Once host exits slow start, time_factor and aggression no longer affect its weight.
  config.core.v3.RuntimeDouble aggression = 2;

  // Configures the minimum percentage of origin weight that avoids too small new weight,
  // which may cause endpoints in slow start mode receive no traffic in slow start window.
  // If not specified, the default is 10%.
  type.v3.Percent min_weight_percent = 3;
}

// Common Configuration for all consistent hashing load balancers (MaglevLb, RingHashLb, etc.)
message ConsistentHashingLbConfig {
  // If set to ``true``, the cluster will use hostname instead of the resolved
  // address as the key to consistently hash to an upstream host. Only valid for StrictDNS clusters with hostnames which resolve to a single IP address.
  bool use_hostname_for_hashing = 1;

  // Configures percentage of average cluster load to bound per upstream host. For example, with a value of 150
  // no upstream host will get a load more than 1.5 times the average load of all the hosts in the cluster.
  // If not specified, the load is not bounded for any upstream host. Typical value for this parameter is between 120 and 200.
  // Minimum is 100.
  //
  // Applies to both Ring Hash and Maglev load balancers.
  //
  // This is implemented based on the method described in the paper https://arxiv.org/abs/1608.01350. For the specified
  // ``hash_balance_factor``, requests to any upstream host are capped at ``hash_balance_factor/100`` times the average number of requests
  // across the cluster. When a request arrives for an upstream host that is currently serving at its max capacity, linear probing
  // is used to identify an eligible host. Further, the linear probe is implemented using a random jump in hosts ring/table to identify
  // the eligible host (this technique is as described in the paper https://arxiv.org/abs/1908.08762 - the random jump avoids the
  // cascading overflow effect when choosing the next host in the ring/table).
  //
  // If weights are specified on the hosts, they are respected.
  //
  // This is an O(N) algorithm, unlike other load balancers. Using a lower ``hash_balance_factor`` results in more hosts
  // being probed, so use a higher value if you require better performance.
  google.protobuf.UInt32Value hash_balance_factor = 2 [(validate.rules).uint32 = {gte: 100}];

  //  Specifies a list of hash policies to use for ring hash load balancing. If ``hash_policy`` is
  // set, then
  // :ref:`route level hash policy <envoy_v3_api_field_config.route.v3.RouteAction.hash_policy>`
  // will be ignored.
  repeated config.route.v3.RouteAction.HashPolicy hash_policy = 3;
}

// Connection overrides for the ORCA out-of-band (OOB) reporting stream, used by
// load balancing policies that consume ORCA load reports (e.g.
// :ref:`client_side_weighted_round_robin
// <envoy_v3_api_msg_extensions.load_balancing_policies.client_side_weighted_round_robin.v3.ClientSideWeightedRoundRobin>`).
// Whether and when OOB reporting runs is controlled by the embedding policy.
message OrcaOobReportingConfig {
  // Optional alternative port for the OOB reporting connection, for example an
  // ORCA reporting sidecar listening on a dedicated port. If 0 or unset, the
  // port of the host's ORCA reporting address is used. Ignored for non-IP
  // (pipe/UDS) host addresses.
  uint32 port_value = 1 [(validate.rules).uint32 = {lte: 65535}];

  // Value of the ``:authority`` header on the OOB gRPC stream. If empty, the
  // endpoint hostname is used, then the dialed address, then the cluster name.
  string authority = 2
      [(validate.rules).string = {well_known_regex: HTTP_HEADER_VALUE strict: false}];

  // Optional key/value pairs used to select a transport socket from the
  // cluster's :ref:`transport_socket_matches
  // <envoy_v3_api_field_config.cluster.v3.Cluster.transport_socket_matches>`
  // for the OOB connection. If unset, or if no match is found, the cluster's
  // default transport socket is used. ALPN ``h2`` is always forced on the OOB
  // connection regardless of this setting.
  google.protobuf.Struct transport_socket_match_criteria = 3;
}
