1
#pragma once
2

            
3
#include "envoy/api/api.h"
4
#include "envoy/common/random_generator.h"
5
#include "envoy/config/bootstrap/v3/bootstrap.pb.h"
6
#include "envoy/config/cluster/v3/cluster.pb.h"
7
#include "envoy/config/core/v3/address.pb.h"
8
#include "envoy/config/core/v3/config_source.pb.h"
9
#include "envoy/config/endpoint/v3/endpoint.pb.h"
10
#include "envoy/config/grpc_mux.h"
11
#include "envoy/config/subscription.h"
12
#include "envoy/local_info/local_info.h"
13
#include "envoy/registry/registry.h"
14
#include "envoy/server/filter_config.h"
15
#include "envoy/upstream/cluster_manager.h"
16

            
17
#include "source/common/common/assert.h"
18
#include "source/common/common/backoff_strategy.h"
19
#include "source/common/common/hash.h"
20
#include "source/common/common/hex.h"
21
#include "source/common/common/utility.h"
22
#include "source/common/protobuf/protobuf.h"
23
#include "source/common/protobuf/utility.h"
24
#include "source/common/runtime/runtime_features.h"
25
#include "source/common/singleton/const_singleton.h"
26
#include "source/common/version/api_version.h"
27
#include "source/common/version/api_version_struct.h"
28

            
29
#include "absl/types/optional.h"
30
#include "udpa/type/v1/typed_struct.pb.h"
31
#include "xds/type/v3/typed_struct.pb.h"
32

            
33
namespace Envoy {
34
namespace Config {
35

            
36
constexpr absl::string_view Wildcard = "*";
37

            
38
/**
39
 * Constant Api Type Values, used by envoy::config::core::v3::ApiConfigSource.
40
 */
41
class ApiTypeValues {
42
public:
43
  const std::string UnsupportedRestLegacy{"REST_LEGACY"};
44
  const std::string Rest{"REST"};
45
  const std::string Grpc{"GRPC"};
46
};
47

            
48
/**
49
 * RateLimitSettings for discovery requests.
50
 */
51
struct RateLimitSettings {
52
  // Default Max Tokens.
53
  static const uint32_t DefaultMaxTokens = 100;
54
  // Default Fill Rate.
55
  static constexpr double DefaultFillRate = 10;
56

            
57
  uint32_t max_tokens_{DefaultMaxTokens};
58
  double fill_rate_{DefaultFillRate};
59
  bool enabled_{false};
60
};
61

            
62
using ApiType = ConstSingleton<ApiTypeValues>;
63

            
64
/**
65
 * General config API utilities.
66
 */
67
class Utility {
68
public:
69
  /**
70
   * Legacy APIs uses JSON and do not have an explicit version.
71
   * @param input the input to hash.
72
   * @return std::pair<std::string, uint64_t> the string is the hash converted into
73
   *         a hex string, pre-pended by a user friendly prefix. The uint64_t is the
74
   *         raw hash.
75
   */
76
2
  static std::pair<std::string, uint64_t> computeHashedVersion(const std::string& input) {
77
2
    uint64_t hash = HashUtil::xxHash64(input);
78
2
    return std::make_pair("hash_" + Hex::uint64ToHex(hash), hash);
79
2
  }
80

            
81
  /**
82
   * Extract initial_fetch_timeout as a std::chrono::milliseconds from
83
   * envoy::config::core::v3::ApiConfigSource. If request_timeout isn't set in the config source, a
84
   * default value of 15s will be returned.
85
   */
86
  static std::chrono::milliseconds
87
  configSourceInitialFetchTimeout(const envoy::config::core::v3::ConfigSource& config_source);
88

            
89
  /**
90
   * Check cluster info for API config sanity.
91
   * @param error_prefix supplies the prefix to use in error messages.
92
   * @param cluster_name supplies the cluster name to check.
93
   * @param cm supplies the cluster manager.
94
   * @param allow_added_via_api indicates whether a cluster is allowed to be added via api
95
   *                            rather than be a static resource from the bootstrap config.
96
   * @return the main thread cluster if it exists, or an error status if problematic.
97
   */
98
  static absl::StatusOr<Upstream::ClusterConstOptRef>
99
  checkCluster(absl::string_view error_prefix, absl::string_view cluster_name,
100
               Upstream::ClusterManager& cm, bool allow_added_via_api = false);
101

            
102
  /**
103
   * Check local info for API config sanity.
104
   * @param error_prefix supplies the prefix to use in error messages.
105
   * @param local_info supplies the local info.
106
   * @return a status indicating if the config is sane.
107
   */
108
  static absl::Status checkLocalInfo(absl::string_view error_prefix,
109
                                     const LocalInfo::LocalInfo& local_info);
110

            
111
  /**
112
   * Check the existence of a path for a filesystem subscription.
113
   * @param path the path to validate.
114
   * @param api reference to the Api object
115
   * @return a status indicating if the path exists.
116
   */
117
  static absl::Status checkFilesystemSubscriptionBackingPath(const std::string& path,
118
                                                             Api::Api& api);
119

            
120
  /**
121
   * Check the validity of a cluster backing an api config source. Throws on error.
122
   * @param primary_clusters the API config source eligible clusters.
123
   * @param cluster_name the cluster name to validate.
124
   * @param config_source the config source typed name.
125
   * @returns failure when an API config doesn't have a statically defined non-EDS cluster.
126
   */
127
  static absl::Status
128
  validateClusterName(const Upstream::ClusterManager::ClusterSet& primary_clusters,
129
                      absl::string_view cluster_name, absl::string_view config_source);
130

            
131
  /**
132
   * Potentially calls Utility::validateClusterName, if a cluster name can be found.
133
   * @param primary_clusters the API config source eligible clusters.
134
   * @param api_config_source the config source to validate.
135
   * @return a status indicating if config is valid.
136
   */
137
  static absl::Status checkApiConfigSourceSubscriptionBackingCluster(
138
      const Upstream::ClusterManager::ClusterSet& primary_clusters,
139
      const envoy::config::core::v3::ApiConfigSource& api_config_source);
140

            
141
  /**
142
   * Gets the gRPC control plane management server from the API config source. The result is either
143
   * a cluster name or a host name.
144
   * @param api_config_source the config source to validate.
145
   * @return the gRPC control plane server, or absl::nullopt if it couldn't be extracted.
146
   */
147
  static absl::optional<std::string>
148
  getGrpcControlPlane(const envoy::config::core::v3::ApiConfigSource& api_config_source);
149

            
150
  /**
151
   * Validate transport_api_version field in ApiConfigSource.
152
   * @param api_config_source the config source to extract transport API version from.
153
   * @returns a failure status when the transport version is disabled.
154
   */
155
2151
  template <class Proto> static absl::Status checkTransportVersion(const Proto& api_config_source) {
156
2151
    const auto transport_api_version = api_config_source.transport_api_version();
157
2151
    ASSERT_IS_MAIN_OR_TEST_THREAD();
158
2151
    if (transport_api_version != envoy::config::core::v3::ApiVersion::AUTO &&
159
2151
        transport_api_version != envoy::config::core::v3::ApiVersion::V3) {
160
5
      const std::string& warning = fmt::format(
161
5
          "V2 xDS transport protocol version is deprecated in {}. "
162
5
          "The v2 xDS major version has been removed and is no longer supported. "
163
5
          "See the advice in https://www.envoyproxy.io/docs/envoy/latest/faq/api/envoy_v3.",
164
5
          api_config_source.DebugString());
165
5
      ENVOY_LOG_MISC(warn, warning);
166
5
      return absl::InvalidArgumentError(warning);
167
5
    }
168
2146
    return absl::OkStatus();
169
2151
  }
170

            
171
  /**
172
   * Parses RateLimit configuration from envoy::config::core::v3::ApiConfigSource to
173
   * RateLimitSettings.
174
   * @param api_config_source ApiConfigSource.
175
   * @return absl::StatusOr<RateLimitSettings> - returns an error when an
176
   *         invalid RateLimit config settings are provided.
177
   */
178
  static absl::StatusOr<RateLimitSettings>
179
  parseRateLimitSettings(const envoy::config::core::v3::ApiConfigSource& api_config_source);
180

            
181
  /**
182
   * Generate a ControlPlaneStats object from stats scope.
183
   * @param scope for stats.
184
   * @return ControlPlaneStats for scope.
185
   */
186
2208
  static ControlPlaneStats generateControlPlaneStats(Stats::Scope& scope) {
187
2208
    const std::string control_plane_prefix = "control_plane.";
188
2208
    return {ALL_CONTROL_PLANE_STATS(POOL_COUNTER_PREFIX(scope, control_plane_prefix),
189
2208
                                    POOL_GAUGE_PREFIX(scope, control_plane_prefix),
190
2208
                                    POOL_TEXT_READOUT_PREFIX(scope, control_plane_prefix))};
191
2208
  }
192

            
193
  /**
194
   * Generate a SubscriptionStats object from stats scope.
195
   * @param scope for stats.
196
   * @return SubscriptionStats for scope.
197
   */
198
12896
  static SubscriptionStats generateStats(Stats::Scope& scope) {
199
12896
    return {ALL_SUBSCRIPTION_STATS(POOL_COUNTER(scope), POOL_GAUGE(scope), POOL_TEXT_READOUT(scope),
200
12896
                                   POOL_HISTOGRAM(scope))};
201
12896
  }
202

            
203
  /**
204
   * Get a Factory from the registry with a particular name (and templated type) with error checking
205
   * to ensure the name and factory are valid.
206
   * @param name string identifier for the particular implementation.
207
   * @param is_optional exception will be throw when the value is false and no factory found.
208
   * @return factory the factory requested or nullptr if it does not exist.
209
   */
210
  template <class Factory>
211
20543
  static Factory* getAndCheckFactoryByName(const std::string& name, bool is_optional) {
212
20543
    if (name.empty()) {
213
1
      ExceptionUtil::throwEnvoyException("Provided name for static registration lookup was empty.");
214
1
    }
215

            
216
20543
    Factory* factory = Registry::FactoryRegistry<Factory>::getFactory(name);
217

            
218
20543
    if (factory == nullptr && !is_optional) {
219
10
      ExceptionUtil::throwEnvoyException(
220
10
          fmt::format("Didn't find a registered implementation for name: '{}'", name));
221
10
    }
222

            
223
20543
    return factory;
224
20543
  }
225

            
226
  /**
227
   * Get a Factory from the registry with a particular name (and templated type) with error checking
228
   * to ensure the name and factory are valid.
229
   * @param name string identifier for the particular implementation.
230
   * @return factory the factory requested or nullptr if it does not exist.
231
   */
232
18592
  template <class Factory> static Factory& getAndCheckFactoryByName(const std::string& name) {
233
18592
    return *getAndCheckFactoryByName<Factory>(name, false);
234
18592
  }
235

            
236
  /**
237
   * Get a Factory from the registry with a particular name or return nullptr.
238
   * @param name string identifier for the particular implementation.
239
   */
240
531789
  template <class Factory> static Factory* getFactoryByName(absl::string_view name) {
241
531789
    if (name.empty()) {
242
      return nullptr;
243
    }
244

            
245
531789
    return Registry::FactoryRegistry<Factory>::getFactory(name);
246
531789
  }
247

            
248
  /**
249
   * Get a Factory from the registry or return nullptr.
250
   * @param message proto that contains fields 'name' and 'typed_config'.
251
   */
252
  template <class Factory, class ProtoMessage>
253
12641
  static Factory* getFactory(const ProtoMessage& message) {
254
12641
    Factory* factory = Utility::getFactoryByType<Factory>(message.typed_config());
255
12641
    if (factory != nullptr ||
256
12641
        Runtime::runtimeFeatureEnabled("envoy.reloadable_features.no_extension_lookup_by_name")) {
257
12639
      return factory;
258
12639
    }
259

            
260
2
    return Utility::getFactoryByName<Factory>(message.name());
261
12641
  }
262

            
263
  /**
264
   * Get a Factory from the registry with error checking to ensure the name and the factory are
265
   * valid. And a flag to control return nullptr or throw an exception.
266
   * @param message proto that contains fields 'name' and 'typed_config'.
267
   * @param is_optional an exception will be throw when the value is false and no factory found.
268
   * @return factory the factory requested or nullptr if it does not exist.
269
   */
270
  template <class Factory, class ProtoMessage>
271
115869
  static Factory* getAndCheckFactory(const ProtoMessage& message, bool is_optional) {
272
115869
    Factory* factory = Utility::getFactoryByType<Factory>(message.typed_config());
273
115869
    if (Runtime::runtimeFeatureEnabled("envoy.reloadable_features.no_extension_lookup_by_name")) {
274
17714
      if (factory == nullptr && !is_optional) {
275
24
        ExceptionUtil::throwEnvoyException(
276
24
            fmt::format("Didn't find a registered implementation for '{}' with type URL: '{}'",
277
24
                        message.name(), getFactoryType(message.typed_config())));
278
24
      }
279
17714
      return factory;
280
111015
    } else if (factory != nullptr) {
281
96487
      return factory;
282
96487
    }
283

            
284
1668
    return Utility::getAndCheckFactoryByName<Factory>(message.name(), is_optional);
285
115869
  }
286

            
287
  /**
288
   * Get a Factory from the registry with error checking to ensure the name and the factory are
289
   * valid.
290
   * @param message proto that contains fields 'name' and 'typed_config'.
291
   */
292
  template <class Factory, class ProtoMessage>
293
76898
  static Factory& getAndCheckFactory(const ProtoMessage& message) {
294
76898
    return *getAndCheckFactory<Factory>(message, false);
295
76898
  }
296

            
297
  /**
298
   * Get type URL from a typed config.
299
   * @param typed_config for the extension config.
300
   */
301
128993
  static std::string getFactoryType(const Protobuf::Any& typed_config) {
302
128993
    static const std::string typed_struct_type(
303
128993
        xds::type::v3::TypedStruct::default_instance().GetTypeName());
304
128993
    static const std::string legacy_typed_struct_type(
305
128993
        udpa::type::v1::TypedStruct::default_instance().GetTypeName());
306
    // Unpack methods will only use the fully qualified type name after the last '/'.
307
    // https://github.com/protocolbuffers/protobuf/blob/3.6.x/src/google/protobuf/any.proto#L87
308
128993
    auto type = std::string(TypeUtil::typeUrlToDescriptorFullName(typed_config.type_url()));
309
128993
    if (type == typed_struct_type) {
310
40
      xds::type::v3::TypedStruct typed_struct;
311
40
      THROW_IF_NOT_OK(MessageUtil::unpackTo(typed_config, typed_struct));
312
      // Not handling nested structs or typed structs in typed structs
313
40
      return std::string(TypeUtil::typeUrlToDescriptorFullName(typed_struct.type_url()));
314
128958
    } else if (type == legacy_typed_struct_type) {
315
2
      udpa::type::v1::TypedStruct typed_struct;
316
2
      THROW_IF_NOT_OK(MessageUtil::unpackTo(typed_config, typed_struct));
317
      // Not handling nested structs or typed structs in typed structs
318
2
      return std::string(TypeUtil::typeUrlToDescriptorFullName(typed_struct.type_url()));
319
2
    }
320
128951
    return type;
321
128993
  }
322

            
323
  /**
324
   * Get a Factory from the registry by type URL.
325
   * @param typed_config for the extension config.
326
   */
327
129409
  template <class Factory> static Factory* getFactoryByType(const Protobuf::Any& typed_config) {
328
129409
    if (typed_config.type_url().empty()) {
329
1542
      return nullptr;
330
1542
    }
331
127867
    return Registry::FactoryRegistry<Factory>::getFactoryByType(getFactoryType(typed_config));
332
129409
  }
333

            
334
  /**
335
   * Translate a nested config into a proto message provided by the implementation factory.
336
   * @param enclosing_message proto that contains a field 'typed_config'. Note: the enclosing proto
337
   * is provided because for statically registered implementations, a custom config is generally
338
   * optional, which means the conversion must be done conditionally.
339
   * @param validation_visitor message validation visitor instance.
340
   * @param factory implementation factory with the method 'createEmptyConfigProto' to produce a
341
   * proto to be filled with the translated configuration.
342
   */
343
  template <class ProtoMessage, class Factory>
344
  static ProtobufTypes::MessagePtr
345
  translateToFactoryConfig(const ProtoMessage& enclosing_message,
346
                           ProtobufMessage::ValidationVisitor& validation_visitor,
347
83232
                           Factory& factory) {
348
83232
    ProtobufTypes::MessagePtr config = factory.createEmptyConfigProto();
349

            
350
    // Fail in an obvious way if a plugin does not return a proto.
351
83232
    RELEASE_ASSERT(config != nullptr, "");
352

            
353
    // Check that the config type is not google.protobuf.Empty
354
83232
    RELEASE_ASSERT(config->GetTypeName() != "google.protobuf.Empty", "");
355

            
356
83232
    THROW_IF_NOT_OK(
357
83232
        translateOpaqueConfig(enclosing_message.typed_config(), validation_visitor, *config));
358
83232
    return config;
359
83232
  }
360

            
361
  /**
362
   * Translate the typed any field into a proto message provided by the implementation factory.
363
   * @param typed_config typed configuration.
364
   * @param validation_visitor message validation visitor instance.
365
   * @param factory implementation factory with the method 'createEmptyConfigProto' to produce a
366
   * proto to be filled with the translated configuration.
367
   */
368
  template <class Factory>
369
  static ProtobufTypes::MessagePtr
370
  translateAnyToFactoryConfig(const Protobuf::Any& typed_config,
371
                              ProtobufMessage::ValidationVisitor& validation_visitor,
372
26042
                              Factory& factory) {
373
26042
    ProtobufTypes::MessagePtr config = factory.createEmptyConfigProto();
374

            
375
    // Fail in an obvious way if a plugin does not return a proto.
376
26042
    RELEASE_ASSERT(config != nullptr, "");
377

            
378
    // Check that the config type is not google.protobuf.Empty
379
26042
    RELEASE_ASSERT(config->GetTypeName() != "google.protobuf.Empty", "");
380

            
381
26042
    THROW_IF_NOT_OK(translateOpaqueConfig(typed_config, validation_visitor, *config));
382
26041
    return config;
383
26042
  }
384

            
385
  /**
386
   * Truncates the message to a length less than default GRPC trailers size limit (by default 8KiB).
387
   */
388
  static std::string truncateGrpcStatusMessage(absl::string_view error_message);
389

            
390
  /**
391
   * Obtain Grpc service config from the api config source.
392
   * @param api_config_source envoy::config::core::v3::ApiConfigSource. Must have config type GRPC.
393
   * @param grpc_service_idx index of the grpc service in the api_config_source. If there's no entry
394
   *                         in the given index, a nullptr factory will be returned.
395
   * @param xdstp_config_source whether the config source will be used for xdstp config source.
396
   *                            These sources must be of type AGGREGATED_GRPC or
397
   *                            AGGREGATED_DELTA_GRPC.
398
   * @return OptRef to either const envoy::config::core::v3::GrpcService or nullptr if there's no
399
   *         grpc_service in the given index.
400
   */
401
  static absl::StatusOr<Envoy::OptRef<const envoy::config::core::v3::GrpcService>>
402
  getGrpcConfigFromApiConfigSource(
403
      const envoy::config::core::v3::ApiConfigSource& api_config_source, int grpc_service_idx,
404
      bool xdstp_config_source);
405

            
406
  /**
407
   * Obtain gRPC async client factory from a envoy::config::core::v3::ApiConfigSource.
408
   * @param async_client_manager gRPC async client manager.
409
   * @param api_config_source envoy::config::core::v3::ApiConfigSource. Must have config type GRPC.
410
   * @param skip_cluster_check whether to skip cluster validation.
411
   * @param grpc_service_idx index of the grpc service in the api_config_source. If there's no entry
412
   *                         in the given index, a nullptr factory will be returned.
413
   * @param xdstp_config_source whether the config source will be used for xdstp config source.
414
   *                            These sources must be of type AGGREGATED_GRPC or
415
   *                            AGGREGATED_DELTA_GRPC.
416
   * @return Grpc::AsyncClientFactoryPtr gRPC async client factory, or nullptr if there's no
417
   *         grpc_service in the given index.
418
   */
419
  static absl::StatusOr<Grpc::AsyncClientFactoryPtr>
420
  factoryForGrpcApiConfigSource(Grpc::AsyncClientManager& async_client_manager,
421
                                const envoy::config::core::v3::ApiConfigSource& api_config_source,
422
                                Stats::Scope& scope, bool skip_cluster_check, int grpc_service_idx,
423
                                bool xdstp_config_source);
424

            
425
  /**
426
   * Translate opaque config from google.protobuf.Any to defined proto message.
427
   * @param typed_config opaque config packed in google.protobuf.Any
428
   * @param validation_visitor message validation visitor instance.
429
   * @param out_proto the proto message instantiated by extensions
430
   * @return a status indicating if translation was a success
431
   */
432
  static absl::Status translateOpaqueConfig(const Protobuf::Any& typed_config,
433
                                            ProtobufMessage::ValidationVisitor& validation_visitor,
434
                                            Protobuf::Message& out_proto);
435

            
436
  /**
437
   * Verify that any filter designed to be terminal is configured to be terminal, and vice versa.
438
   * @param name the name of the filter.
439
   * @param filter_type the type of filter.
440
   * @param filter_chain_type the type of filter chain.
441
   * @param is_terminal_filter true if the filter is designed to be terminal.
442
   * @param last_filter_in_current_config true if the filter is last in the configuration.
443
   * @return a status indicating if there is a mismatch between design and configuration.
444
   */
445
  static absl::Status validateTerminalFilters(const std::string& name,
446
                                              const std::string& filter_type,
447
                                              const std::string& filter_chain_type,
448
                                              bool is_terminal_filter,
449
                                              bool last_filter_in_current_config);
450

            
451
  /**
452
   * Prepares the DNS failure refresh backoff strategy given the cluster configuration.
453
   * @param config the config that contains dns refresh information.
454
   * @param dns_refresh_rate_ms the default DNS refresh rate.
455
   * @param random the random generator.
456
   * @return BackOffStrategyPtr for scheduling refreshes.
457
   */
458
  template <typename T>
459
  static BackOffStrategyPtr prepareDnsRefreshStrategy(const T& config, uint64_t dns_refresh_rate_ms,
460
641
                                                      Random::RandomGenerator& random) {
461
641
    if (config.has_dns_failure_refresh_rate()) {
462
24
      uint64_t base_interval_ms =
463
24
          PROTOBUF_GET_MS_REQUIRED(config.dns_failure_refresh_rate(), base_interval);
464
24
      uint64_t max_interval_ms = PROTOBUF_GET_MS_OR_DEFAULT(config.dns_failure_refresh_rate(),
465
24
                                                            max_interval, base_interval_ms * 10);
466
24
      if (max_interval_ms < base_interval_ms) {
467
2
        ExceptionUtil::throwEnvoyException(
468
2
            "dns_failure_refresh_rate must have max_interval greater than "
469
2
            "or equal to the base_interval");
470
2
      }
471
24
      return std::make_unique<JitteredExponentialBackOffStrategy>(base_interval_ms, max_interval_ms,
472
24
                                                                  random);
473
24
    }
474
617
    return std::make_unique<FixedBackOffStrategy>(dns_refresh_rate_ms);
475
641
  }
476

            
477
  /**
478
   * Returns Jittered Exponential BackOff Strategy from BackoffStrategy config if present or
479
   * provided default timer values
480
   * @param api_config_source config
481
   * @param random random generator
482
   * @param default_base_interval_ms  Default base interval, must be > 0
483
   * @param default_max_interval_ms (optional) Default maximum interval
484
   * @return JitteredExponentialBackOffStrategyPtr if 1. Backoff Strategy is
485
   * found in the config or 2. default base interval and default maximum interval is specified or 3.
486
   * max interval is set to 10*default base interval
487
   */
488
  static absl::StatusOr<JitteredExponentialBackOffStrategyPtr>
489
  prepareJitteredExponentialBackOffStrategy(
490
      const envoy::config::core::v3::ApiConfigSource& api_config_source,
491
      Random::RandomGenerator& random, const uint32_t default_base_interval_ms,
492
1713
      absl::optional<const uint32_t> default_max_interval_ms) {
493
1713
    auto& grpc_services = api_config_source.grpc_services();
494
1713
    if (!grpc_services.empty() && grpc_services[0].has_envoy_grpc()) {
495
1112
      return prepareJitteredExponentialBackOffStrategy(
496
1112
          grpc_services[0].envoy_grpc(), random, default_base_interval_ms, default_max_interval_ms);
497
1112
    }
498
601
    return buildJitteredExponentialBackOffStrategy(absl::nullopt, random, default_base_interval_ms,
499
601
                                                   default_max_interval_ms);
500
1713
  }
501

            
502
  /**
503
   * Prepares Jittered Exponential BackOff Strategy from config containing the Retry Policy
504
   * @param config config containing RetryPolicy <envoy_v3_api_msg_config.core.v3.RetryPolicy>
505
   * @param random random generator
506
   * @param default_base_interval_ms  Default base interval, must be > 0
507
   * @param default_max_interval_ms (optional) Default maximum interval
508
   * @return JitteredExponentialBackOffStrategyPtr if 1. RetryPolicy containing backoff values is
509
   * found in config or 2. default base interval and default maximum interval is specified or 3.
510
   * default max interval is set to 10*default base interval
511
   */
512
  template <typename T>
513
  static absl::StatusOr<JitteredExponentialBackOffStrategyPtr>
514
  prepareJitteredExponentialBackOffStrategy(
515
      const T& config, Random::RandomGenerator& random, const uint32_t default_base_interval_ms,
516
1161
      absl::optional<const uint32_t> default_max_interval_ms) {
517
    // If RetryPolicy containing backoff values is found in config
518
1161
    if (config.has_retry_policy() && config.retry_policy().has_retry_back_off()) {
519
54
      return buildJitteredExponentialBackOffStrategy(config.retry_policy().retry_back_off(), random,
520
54
                                                     default_base_interval_ms,
521
54
                                                     default_max_interval_ms);
522
54
    }
523
1107
    return buildJitteredExponentialBackOffStrategy(absl::nullopt, random, default_base_interval_ms,
524
1107
                                                   default_max_interval_ms);
525
1161
  }
526

            
527
private:
528
  /**
529
   * Returns Jittered Exponential BackOff Strategy from BackoffStrategy config or default
530
   * values
531
   * @param config (optional) BackoffStrategy config
532
   * @param random random generator
533
   * @param default_base_interval_ms  Default base interval, must be > 0
534
   * @param default_max_interval_ms (optional) Default maximum interval
535
   * @return JitteredExponentialBackOffStrategyPtr if 1. Backoff Strategy is
536
   * specified or 2. default base interval and default maximum interval is specified or 3.
537
   * max interval is set to 10*default base interval
538
   */
539
  static absl::StatusOr<JitteredExponentialBackOffStrategyPtr>
540
  buildJitteredExponentialBackOffStrategy(
541
      absl::optional<const envoy::config::core::v3::BackoffStrategy> backoff,
542
      Random::RandomGenerator& random, const uint32_t default_base_interval_ms,
543
      absl::optional<const uint32_t> default_max_interval_ms);
544
};
545
} // namespace Config
546
} // namespace Envoy