// Copyright 2025 Envoy Project Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
//     http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

syntax = "proto3";

package envoy.extensions.load_balancing_policies.client_side_weighted_round_robin.v3;

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

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

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

// [#protodoc-title: Client-Side Weighted Round Robin Load Balancing Policy]
// [#extension: envoy.load_balancing_policies.client_side_weighted_round_robin]

// Configuration for the client_side_weighted_round_robin LB policy.
//
// This policy differs from the built-in ROUND_ROBIN policy in terms of
// how the endpoint weights are determined. In the ROUND_ROBIN policy,
// the endpoint weights are sent by the control plane via EDS. However,
// in this policy, the endpoint weights are instead determined via qps (queries
// per second), eps (errors per second), and utilization metrics sent by the
// endpoint using the Open Request Cost Aggregation (ORCA) protocol. Utilization
// is determined by using the ORCA application_utilization field, if set, or
// else falling back to the cpu_utilization field. All queries count toward qps,
// regardless of result. Only failed queries count toward eps. A config
// parameter error_utilization_penalty controls the penalty to adjust endpoint
// weights using eps and qps. The weight of a given endpoint is computed as:
// ``qps / (utilization + eps/qps * error_utilization_penalty)``.
//
// Note that Envoy will forward the ORCA response headers/trailers from the upstream
// cluster to the downstream client. This means that if the downstream client is also
// configured to use ``client_side_weighted_round_robin`` it will load balance against
// Envoy based on upstream weights. This can happen when Envoy is used as a reverse proxy.
// To avoid this issue you can configure the :ref:`header_mutation filter  <envoy_v3_api_msg_extensions.filters.http.header_mutation.v3.HeaderMutation>` to remove
// the ORCA payload from the response headers/trailers.
//
// See the :ref:`load balancing architecture
// overview<arch_overview_load_balancing_types>` for more information.
//
// [#next-free-field: 8]
message ClientSideWeightedRoundRobin {
  // Whether to enable out-of-band utilization reporting collection from
  // the endpoints. By default, per-request utilization reporting is used.
  google.protobuf.BoolValue enable_oob_load_report = 1;

  // Load reporting interval to request from the server. Note that the
  // server may not provide reports as frequently as the client requests.
  // Used only when enable_oob_load_report is true. Default is 10 seconds.
  google.protobuf.Duration oob_reporting_period = 2;

  // A given endpoint must report load metrics continuously for at least
  // this long before the endpoint weight will be used. This avoids
  // churn when the set of endpoint addresses changes. Takes effect
  // both immediately after we establish a connection to an endpoint and
  // after weight_expiration_period has caused us to stop using the most
  // recent load metrics. Default is 10 seconds.
  google.protobuf.Duration blackout_period = 3;

  // If a given endpoint has not reported load metrics in this long,
  // then we stop using the reported weight. This ensures that we do
  // not continue to use very stale weights. Once we stop using a stale
  // value, if we later start seeing fresh reports again, the
  // blackout_period applies. Defaults to 3 minutes.
  google.protobuf.Duration weight_expiration_period = 4;

  // How often endpoint weights are recalculated. Values less than 100ms are
  // capped at 100ms. Default is 1 second.
  google.protobuf.Duration weight_update_period = 5;

  // The multiplier used to adjust endpoint weights with the error rate
  // calculated as eps/qps. Configuration is rejected if this value is negative.
  // Default is 1.0.
  google.protobuf.FloatValue error_utilization_penalty = 6 [(validate.rules).float = {gte: 0.0}];

  // By default, endpoint weight is computed based on the :ref:`application_utilization <envoy_v3_api_field_.xds.data.orca.v3.OrcaLoadReport.application_utilization>` field reported by the endpoint.
  // If that field is not set, then utilization will instead be computed by taking the max of the values of the metrics specified here.
  // For map fields in the ORCA proto, the string will be of the form ``<map_field_name>.<map_key>``. For example, the string ``named_metrics.foo`` will mean to look for the key ``foo`` in the ORCA :ref:`named_metrics <envoy_v3_api_field_.xds.data.orca.v3.OrcaLoadReport.named_metrics>` field.
  // If none of the specified metrics are present in the load report, then :ref:`cpu_utilization <envoy_v3_api_field_.xds.data.orca.v3.OrcaLoadReport.cpu_utilization>` is used instead.
  repeated string metric_names_for_computing_utilization = 7;
}
